C语言学习总结
一、 数据类型、运算符与表达式
1、 数据类型:基本类型(整型、浮点型、字符型)、构造类型(数组、struct、union、enum)、指针类型、空类型void
2、 运算符:
Ø 算术运算符:*、 -、 +、 /、 %、 ++、 --
Ø 复合运算符:+=、 -=、 *=、 /=、 %=
Ø 关系运算符: > < == != >= <=
Ø 逻辑运算符:! &&||
Ø 位运算符:<<>> ~ | ^ &
Ø 赋值运算符:=及扩展赋值运算符
Ø 条件运算符:?:
Ø 逗号运算符:,
Ø 指针运算符:*和&
Ø 求字节数运算符:sizeof
Ø 强制类型转换运算符:(类型)
Ø 分量运算符:. ->
Ø 下标运算符:[ ]
注:条件运算符是C语言中惟一一个三目(三元)运算符
3、 表达式: 常量、变量、运算符的组合(每个表达式都会有运算结果)
Ø 常量:程序运行期间值不能被改变的量
Ø 变量:程序运行期间值可以改变的量(变量代表着一个存储区域,存储区域内存储的内容就是变量的值)
4、 格式化输入(scanf)、输出(printf)函数使用scanf输入的时候,系统只识别大回车
二、 分支结构
1、 程序执行顺序:
Ø 顺序:自上而下
Ø 分支:根据判定条件选择执行代码
Ø 循环:某些代码执行多次
2、 if分支结构(根据给定的条件进行判定,用以决定执行哪个分支程序段)包括if(表达式){语句;}、if(表达式){语句一;} else{语句二;if(表达式){语句一;}elseif{语句二;}等表示形式
3、 switch case(多选一分支结构)通常会用break结束case语句
三、 循环结构(在给定的条件成立时反复执行某程序段,直到条件不成立为止)
1、 for循环:for(循环变量初值;循环条件;循环变量增量){语句;}
通常用于知道循环次数的情况
2、 while循环(表达式){语句;}
通常用于不知道循环次数的情况
3、 continue、break
Ø break:主要用于跳出本次循环,执行循环后面的语句
Ø continue:结束本次循环,进入下次循环(通常与if一起使用,用于加速循环)
四、 数组(是一种构造类型,相同数据类型组成的一组数据,数组每个成员成为数组元素)
1、 一维数组
定义:类型说明符 数组名[常量表达式] = {值1,值2····};
字符数组的定义:char c[10] = {‘I’,’P’,’h’,’o’,’n’,’e’,’\0’};
或者char c[10] = “iphone”;
字符串函数有:strlen()(计算字符串长度,算出的值不包括’\0’)、strcpy()、strcat()、strcmp()等
2、 二维数组
定义:类型说明符 数组名[常量表达式1][常 量表达式2] = {值1,值2...};
3、 遍历数组元素
数组定义后,我们不能对数组进行整体的操作,如int a[10];不能用a=3这样的操作将数组的各元素都赋值为3;而只能一个一个元素的进行赋值,如a[0]=3;a[1]=3;a[2]=3…a[9]=3; 当然此时我们就可以借助于一个for循环来控制下标的变化从而对数组的各个元素进行赋值
字符串数组:是存放字符串的数组(a[0]代表第一个字符串)
数组的下标(从0开始,一直到数组总数-1)必须为一个定值不能为变量,可以是常量表达式,数组名为数组首地址
数组所占内存 = 元素个数 * 单个元素所占空间
voidbublle_sort(int a[],intn){//n为数组a的元素个数
inti,j,temp;
for(j=0;j<n-1;j++){
for(i=0;i<n-1-j;i++){
if(a[i]>a[i+1]){//数组元素大小按升序排列
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
}
}
五、 函数(具有特定功能的代码块,功能大大简化程序,提高开发效率)
1、 函数定义
函数类型 函数名( 形式参数列表 )
{
内部变量定义和声明部分
执行语句
}
如:
int max (intx , int y )
{ int z
z = x > y ? x : y
return z;
}
注意点:
Ø 函数类型是指返回值的类型,即要与return语句后跟的表达式的值的类型一致。若函数类型为void则说明该函数无返回值,即函数体里不能出现return 语句。 2.形式参数列表里定义的变量要记得给它们指定类型,而且如果同时要定义多个,应在每个前面都分别指定类型名,而不能写成int x,y;
Ø 函数体里能写的语句跟main函数一样,在开头可定义所需要的变量,后面跟上一堆执行语句。
2、 函数调用流程
以上面的函数为例,在main函数进行调用:
void main()
{ int a,b,c;
scanf(“%d%d”,&a,&b);
printf(“%d”,max(a,b)); //或 c=max(a,b);printf(“%d”,c)
}
以上两种方法都会在屏幕中打印出a,b间的较大值。
调用函数的格式: 函数名(实际参数列表);调用的时候像什么函数类型,形式参数的类型就不要加上去了。max(a,b)中max就是函数名,写上变量名a,b是实际参数列表,执行这个调用语句时,会先把a,b的值给相应位置的形式参数即执行了x=a,y=b这样的操作,然后开始执行max函数的函数体的语句。当max函数体里执行到一个return语句时,则max函数结束执行,将return后的表达式的值返回给main函数调用max函数的那个位置,即若上面a=3,b=5则max(a,b)return后的表达式的值应该是5也就是说执行完max后把5返回到调用max的位置可看成printf(“%d”,5);或另一种解法的c=5
六、 指针
1、 指针变量的声明: 类型名 * 指针变量名;
2、 通过指针变量访问它所指向的普通变量的值
先将普通变量的地址赋值给指针变量,再通过指针运算符* 得到普通变量的值。 int *p,x,y; x=3; p=&x;
则printf(“%d”,*p);会打印出3即x的值 y=*p;则y的值变为3 *p=5;则x的值变为5
3、 指针变量加上(减去)一个位移的效果
若指针变量存入的是数组元素的地址,则其加一减一得到的是那个数组元素下一个或前一个元素的地址。 int a[10]; p=&a[3];
*p得到的是a[3]的值。 若p++;此时p存放的是a[4]的地址&a[4]; *p得到的就是a[4]的值。 或p--;此时p存放的是a[2]的地址&a[2],*p得到的就是a[2]的值。
4、 行指针
Ø 主要是对于二维数组来说的,二维数组每行都有自己的地址,第0行地址用 数组名 表示,第i行地址为 数组名+i;而想要得到二维数组里一个元素的地址,必需先得到其所在行的地址,然后再由那个地址得到元素的地址,比如说 int a[3][4];定义了一个二维数组,该二维数组第0行的地址为a,第1行的地址为a+1,第2行的地址为a+2,想从行的地址得到元素的地址,需在行地址前加上指针运算符“*”,即*a就是第0行首个元素的地址即a[0][0]的地址,而a[0][2]的地址就是在a[0][0]的地址基础上加上位移量2,即*a+2,然后想得到a[0][2]这个元素的值呢就再加上一个指针运算符“*”,即*(*a+2),类似地,想得到a[2][2]这个元素的值呢就是*(*(a+2)+2)
Ø 定义行指针变量: 类型名 (*变量名)[数组长度];
如int (*p)[4],a[3][4]; p=a;此时就可把p当成a来用,用法同上所述。
5、 指针数组:指针数组的数组元素都是指针变量,是用来存放变量的地址的,定义格式为 类型名 * 变量名[数组长度]; 如int * p[10];
6、 指向指针的指针:指针变量也是一种变量,故在内存中也有对应的一个地址,而要存放指针变量的地址,就要求助于用来存放指针变量的地址的指针变量,定义格式 类型名 ** 变量名;如 int *p1; int **p2; int a=3;可进行赋值p1=&a; p2=&p1; 则a 、*p1和 **p2的值都是3.
七、 动态内存分配
1、 存储区划分:栈区、堆区、全局区(静态区)、常量区、代码区
Ø 栈区:由编译器自动分配和释放,栈中的变量先进后出
Ø 堆区:一般有程序员分配和释放(malloc、calloc、realloc)
² 初始化的全局变量和静态变量在一块区域;未初始化的全局变量和未初始化的静态变量在相邻的另一块区域
² void *malloc(sizeof(int)):函数向系统申请分配size个连续的内存空间
² void *calloc(unsigned n,unsigned size):分配n个size大小的空间
² void *realloc(void *p,unsignednewSize):按新的长度重新分配内存
² 返回值void * :属于指针类型,不代表确切的指针类型,程序员根据需要强行转换称自己需要的类型
² 释放堆内存:free(str); //标记删除,不清楚内容
Ø 常量区:专门存放常量的地方(此块区域的值初始化后不能改)
Ø 程序代码区:存放二进制代码的区域
2、 内存操作函数(既可以用于堆内存,也可以用于栈内存)
Ø void *memset(void *s, int c,size_t n):为s开始长度为n的所有字节赋值为c(通常用于清除结构体或者数组数据)
Ø void *memcpy(void *dest,constvoid *source , size_t n):从source拷贝n个字节到dest中
Ø int memcmp(const void *buf1,const void *buf2, unsigned int count):内存比较,比较结果分 >0、<0、=0
八、 宏定义
1、 无参宏定义:#define 标识符 值 定义后,出现所定义的标识符的地方都将以定义时指定的值来代替。
2、 带参宏定义:#define 标识符(参数表) 值(要注意打括号)
4、 自定义类型名typedef:对已存在的类型名取一个外号。
九、 结构体、枚举
1、 结构体:
1、 结构体类型的定义及变量的定义 :
struct 结构体名 {类型 成员1;
类型 成员2; ……
类型 成员n; }变量名;
2、 结构体变量所占字节数:以结构体中占字节数最大的值为标准,按这个大小的字节数按顺序分配
3、 结构体变量初始化:struct student a={20030001, "张三", 70,75,80,85};
4、 结构体数组定义及初始化:
struct student a[3]={{20030001,"zhang",89,90,91,92}, {20030002,"liu",68,69,70,71},
{20030003,"li",57,58,59,60} };
5、 结构体变量成员的访问
2、 枚举
6、 枚举类型的定义:
enum 枚举名{枚举元素名1,枚举元素名2,…,枚举元素名n};
7、 枚举元素的值:
默认值分别为0、1、…、n-1。枚举元素的值也可在定义时重指定,对于没有指定值的元素,按顺序加1
十、 函数指针(函数名代表函数的内存地址(入口地址))
1、 函数指针定义:int (*p)(int x,int y) = NULL
p为指向函数的指针变量,int (*)(int x,int y)为类型,NULL是初值
通常使用typedef来定义函数指针类型
typedef int(*PFUN)(int x,int y);//形参可省略
PFUN是typedef后的新类型名 PFUN p = NULL;
2、 回调函数(callback):回调函数是一个函数,由调用方自己实现,供被调用方调用的函数
如:int getValue(int a,int b,int(*p)(int,int));
使用:int m = getValue(3,5,maxValue); //m是5
3、 函数指针数组:
Ø int (*p[3])(int,int) ={0};
可改为:
typedef int(*PFUN)(int,int);
PFUN p[3] = {0};
p[0] = maxValue;
p[1] = sum;
Ø int (*functionName(inta))(int, int);
可改为
typedef int(*PFUN)(int,int);
PFUN functionName(int a);