C语言学习
printf("i=%d\n",i);
/*
printf的用法
- %d表示以十进制输出
- %x或%X表示以十六进制输出
- %o表示以八进制输出
*/
- 十六进制:在前面加上0x或0X;
- 八进制:在前面加数字 0
字符
单个字符用单引号括起来
'a' 表示字符a
'ab' 错误
字符串用双引号括起来
"a"正确,因为"a"代表了'a' '\0' 的组合
#include <stdio.h>
int main(void)
{
int x=47; //100是十进制
printf("%x\n",x); //输出结果2f
printf("%X\n",x); //输出结果2F
printf("%#x\n",x); //输出结果0x2f
printf("%#X\n",x); //输出结果0X2F,推荐使用
return0;
}
为什么需要输出控制符:
- 01组成的代码可以表示数据也可以表示指令;
- 如果01组成的代码表示的是数据的话,那么同样的01代码组合以不同的输出格式输出就会有不同的输出结果
输出控制符包含如下:
%d——int(整型)
%ld——long int (长整型)
%c—— char(短整型)
%f——float(单精度)
%lf——double(双精度)
%x(或者%X,%#X)—— int或 long int 或short int
%o——同上
%s——字符串
scanf():通过键盘将数据输入到变量中
两种用法:
用法一:scanf("输入控制符",输入参数);
功能:将从键盘输入的字符转化为输入控制符所规定的数据,然后存入以输入参数的值为地址的变量中
‘ scanf("%d",&i); //&i表示i的地址,&是一个取地址符 ’
用法二:scanf("非输入控制符 输入控制符",输入参数);//非输入控制符必须原样输入,同时无需像printf那样添加\n
' scanf("m%d",&i); //m123正确的输入,123非法的输入,输入结果为123 '
功能:将从键盘输入的字符转化为输入控制符所规定的数据,然后存入以输入参数的值为地址的变量中
scanf中尽量不要使用非输入控制符,尤其是不要用\n
除法与取模运算
- 除法 / 的运算结果和运算对象的数据类型有关,两个都是int,则商也是int;若商有小数,则删除小数部分;被除数和除数中只要有一个或两个都是浮点型数据,则商也是浮点型,不删除小数部分
- 取余 % 的运算对象必须是 整数 ,如:1.5/2 错误; 结果是整除后的余数,其余数的符号与被除数相同
逻辑运算符
& 取地址符
&& 并且
|| 或
&&左边的表达式为假时,右边表达式不执行;||左边表达式为真时,右边表达式不执行。
优先级别:算术>关系>逻辑>赋值
自增 自减 三目运算符 逗号表达式
自增:i++ 或 i--(i++和++i单独成一个语句,不要把它们作为一个完整复合语句的一部分来使用)
三目运算符:A?B:C 等价于 if(A)
B;
else
C;
逗号表达式:
格式:(A,B,C,D)
功能:从左到右执行,最终表达式的值是最后一项的值。
流程控制(学习C语言的第一个重点)
1.什么是流程控制
程序代码执行的顺序
2.流程控制的分类
顺序
选择
循环
注意:
if (a>0)
printf("大于\n");
printf("哈哈\n");
else if(a==0)
printf("等于\n");//编译错误,else没有相匹配的if
if (a>0)
{
printf("大于\n");
printf("哈哈\n");
}
else if(a==0)
printf("等于\n");//编译正确
注意:
大于90小于100不能写成90<=score<=100;应写成 score>=90&&score<=100
一些小算法的程序:
1、判断一个数字是否是素数;
2、判断一个数字是否是回文数,如121;
3、编程实现求一个十进制数的二进制形式;
4、求一个数字的每位是奇数的数字取出来组合成的新数字;
5、求一个数字倒过来 的数字
if常见的问题解析
1、空语句的问题
if (3>2);
等价于
if (3>2)
; //这是一个空语句
注意: 最后一个else的用法:
直接单个的else 或 else if+(表达式)//后者语法不会出错,但逻辑有漏洞
强制类型转换
格式:(数据类型)(表达式)
功能:把表达式的值强制转化为前面所执行的数据类型
例子:(int)(4.5+2.2) 结果为6
(float)(5)结果为5.000000
浮点数的存储所带来的问题:
1、 float和 double都不能保证可以精确的存储一个小数
例子:
float i=99.9;
printf("%f\n",i);
输出结果为:99.900002
举例:判断浮点型变量x的值是否为0:
if(|x-0.0000001|<=0.0000001)
是0;
else
不是0;
2、为什么循环中更新的变量不能定义成浮点型?
for和while的区别:
for(1;2;3)
A;
等价于
1;
while(2)
{
A;
3;
}
while和for可以相互转化,但for的逻辑性更强,更不容易出错,推荐多使用for。
do...while...
格式:do
{
....
} while ( 表达式);
注意:do...while...并不等价于for,也不等价于while。
switch语句(自己百度)
break和continue
break:
1、如果用于循环使用来终止循环;
2、如果用于switch,则是用于终止 switch
3、break不能直接用于if,除非if属于循环内部的一个字句
例子:
for(i=0;i<3;++i)
{
if(3>2)
break; //break虽然是if内部的语句,但 终止的是外部的for循环
printf("嘿嘿!\n");//永远不会输出
}
4、在多层循环或者多层switch语句中,break只能终止距离它最近的循环或者switch语句
在多层switch嵌套中break只能终止距离它最近的switch语句
continue:
用于跳过本次循环余下的语句,转去判断是否需要执行下次循环
数组
数组定义:
为n个变量连续分配存储空间
所有的变量数据类型必须相同
所有变量所占字节大小必须相同
错误写法:
int a[5];
a[5]={1,2,3,4,5}; //错误,a[5]元素不存在
只有在定义数组的同时才可以整体赋值,其他情况下整体赋值都是错误的
int a[5]={1,2,3,4,5};
int b[5];
如果要把a数组的值全部复制给b数组
错误的写法:
b=a; // error
正确的写法:
for(i=0;i<5;++i)
b[i]=a[i];
一维数组名不代表数组中的所有元素,仅代表数组第一个元素的地址
多维数组:
n维数组可以当作每个元素是n-1维数组的一维数组
函数
int f (void) // 括号中的void表示该函数不能接受数据,int表示函数返回值是int类型
{
}
void g (void) //函数名前面的void表示该函数没有返回值
{
}
函数定义
函数的返回值 函数名 (函数的形参列表)
{
函数的执行体
}
函数返回值的类型也称为函数的类型,因为如果 函数名 前的返回值类型和 函数执行体 中的 return表达式; 中表达式的类型不同的话,则最终函数返回值的类型以 函数名 前的返回值类型为准
return:
1>终止被调函数,向被调函数返回表达式的值;
2>如果表达式为空,则只终止函数,不向被调函数返回任何值;
3>break是用来终止循环和switch的,return是用来终止函数的
一个程序必须有且只能有一个主函数;
主函数可以调用普通函数,普通函数不能调用主函数;
普通函数可以相互调用
主函数是程序的入口,也是程序的出口
函数调用和函数定义的顺序:
如果函数调用写在了函数定义的前面,则必须加函数前置声明
函数前置声明:
1、告诉编译器即将可能出现的若干个字母代表的是一个函数;
2、告诉编译器即将可能出现的若干个字母所代表的函数的形参和返回值的具体情况
3、函数声明是一个语句,末尾必须加分号;
4、对库函数的声明是通过 # include<库函数所在的文件名字.h>来实现的
形参和实参;
个数相同 位置一一对应 数据类型必须相互兼容
注意 函数是C语言的基本单位,类是Java,c#,c++的基本单位
常用的系统函数使用(百度)
变量的作用域和存储方式:
按作用域分:
全局变量:在所有函数外部定义的变量叫做全局变量
全局变量使用范围:从定义位置开始到整个程序结束
局部变量:在一个函数内部定义的变量或者函数的形参 都统称为局部变量
void f (int i)
{
int j=20;
}
i,j都属于局部变量
局部变量使用范围:只能在本函数内部使用
全局变量和局部变量命名冲突的问题
在一个函数内部如果定义的局部变量的名字和全局变量的名字一样时,局部变量会屏蔽掉全局变量
指针 (C语言的灵魂)
include<stdio.h>
int main(void)
{
int *p;//p是变量的名字,int *表示p变量存放的是int类型变量的地址
//int *p: 不表示定义了一个名字叫做 *P 的变量
//int P: p是变量名,p变量的数据类型是int * 类型
//所谓int 类型就是存放int变量地址的类型
int i=3;
p=&i;
/
1.p保存了i的地址,因此p指向i
2.p不是i,i也不是p,修改p的值不影响i的值,修改i的值不影响p的值
3.如果一个指针变量指向了某个普通变量,则
指针变量 就完全等同于 普通变量
例子:如果p是一个指针变量,并且p存放了普通变量i的地址
则p指向了普通变量i
* p 就完全等同于 i
即在所有出现p的地方都可以替换成 i
在所有出现 i 的地方都可以替换成p
*p (即 i)就是以 p 的内容为地址的变量
*/
}
注意:
1、指针就是地址,地址就是指针
2、地址就是内存单元的编号
3、指针变量是存放地址的变量
4、指针和指针变量就是两个不同的概念
5、要注意的是,通常我们叙述时可能会把指针变量简称为指针,实际它们含义不一样
6、指针的本质就是一个操作受限的非负整数
include<stdio.h>
void huhuan(int P, int q )
{
int t ;//如果要互换p和q的值,则t必须定义成int,不能定义成int ,否则出错
t=p; // p是 int * 类型, p是 int类型
p=q;
q=t;
}
int main (void)
{
int a=3;
int b=5;
huhuan(&a,&b); //huhuan(p,q); 是错误的,huhuan(a,b); 也是错误的
printf("a=%d,b=%d\n",a,b);
return 0;
}
附注
* 的定义
1、乘法;
2、定义指针变量
int *p; //定义了一个名字叫做p的变量,int *表示p只能存放 int 变量的地址
3、指针运算符
该运算符放在已经定义好的指针变量的前面,如 P=i
如果p是一个已经定义好的指针变量,则p 表示以p的内容为地址的变量,即 i;
如何通过被调函数修改主调函数普通函数的值
1、实参必须为该普通变量的地址;
2、形参必须为指针变量
3、在被调函数中通过
*形参名 = ..... 的方式就可以修改主调函数相关变量的值
指针和数组
指针和一维数组:
一维数组名: 它是一个指针常量,存放的是一维数组的第一个元素的地址
下标和指针的关系
如果p是个指针变量,则p[i] 永远等价于 *(p+i)
确定一个一维数组需要几个参数
两个参数: 数组第一个元素的地址、 数组的长度
*(parr+i)等价于 parr[i]
指针变量的运算
指针变量不能相加,不能相乘,也不能相除
如果两个指针变量指向的是同一块连续空间的不同存储单元,则这两个指针变量才可以相减
一个指针变量到底占几个字节
p指向char类型变量:一个字节
q指向int类型变量:四个字节
r指向double类型变量:八个字节
p,q,r本身所占的字节数是否一样?
答案:p q r本身所占的字节数是一样的
sizeof(数据类型)
功能:返回值是该数据类型所占的字节数
sizeof(变量名)
功能:返回值是该变量所占的字节数
例如:sizeof(int)=4
总结
1、 一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占 四 个字节(32位数据线表示地址,即32/8=4 个字节)
2、 一个变量的地址使用该变量首字节的地址来表示
动态内存分配
传统数组的缺点:
1、传统形式定义的数组,该数组的内存程序员无法手动释放,在一个函数运行期间,系统为该函数所分配的空间会一直存在,知道该函数运行完毕,数组的空间才会被系统释放
2、 传统方式定义的数组不能跨函数使用
malloc函数 是memory(内存) allocate(分配)的缩写
1、使用malloc函数,必须添加malloc.h这个头文件
2、malloc函数只有一个形参,并且形参是整型
3、malloc(4) 表示请求系统为本程序分配4个字节
4、malloc函数只能返回第一个字节的地址
free(p)表示把p指向的内存给释放掉,但不能把p本身所占的内存给释放,其在程序结束时由系统自动释放。
动态分配和静态分配的比较
静态内存是由系统自动分配,由系统自动释放;
静态内存是在 栈 分配的
动态内存是由程序员手动分配,手动释放
动态内存是在 堆 分配的(函数终止时不释放内存)
结构体
3种方式(推荐第一种):
1、struct Student //定义了一个数据类型,而不是一个变量
{
int age;
float score;
char sex;
};
2、 struct Student
{
int age;
float score;
char sex;
}st;
3、struct
{
int age;
float score;
char sex;
} st;
如何取出结构体变量中的每一个成员?
1、结构体变量名 . 成员名
2、指针变量名->成员名 (常用)
3、指针变量名->成员名 在计算机内部会被转换成 (* 指针变量名). 成员名 的方式来执行
例如:
st.age=10;
pst->age=88; // 前面有 struct Student * pst=&st;
pst->age在计算机内部会被转换成(*pst).age
结构体变量和结构体指针变量作为函数参数传递的问题
推荐使用结构体指针变量作为函数参数来传递
结构体变量的运算
结构体变量不能相加,不能相减,也不能相互乘除
但结构体变量可以相互赋值。