C语言的学习整理
·DAY_1 C语言数据类型
#import
导入框架,框架下包含了很多方法以及函数
main()
主函数:程序的出口和入口
一、数据类型
数据类型 所占字节数 英文
字符型 1 char
整型 4 int
长整型 4/8 long
短整型 2 short
单精度浮点型 4 float
双精度浮点型 8 double
long所占的字节数跟操作系统位数有关,32位占4个字节,64位占8个字节。
字节数:所能表示的最大数,最小数范围不一样
二、常量,变量
常量:程序运行期间值不能被改变
变量:程序运行期间值能够被改变。
是一个容器(存储区域),值就是容器里面的内容。
变量的定义
语法:变量类型 变量名 = 初值;
定义一个整型变量:int a = 0;
定义一个浮点型变量:float b = 1.01;
定义一个字符型变量:char c = ‘a’;
打印输出
printf(“%d,%f,%c”,a,b,c);
变量名的命名规范:
1、在同一个作用域内不能重命名
2、由数字,字母,下划线组成,但是不能以数字开头
3、见名知意
4、不能与系统保留字同名
三、运算符
1、赋值运算符 =
2、算术运算符
+(加),-(减),*(乘);
/(除,取整,除数不能为0);
%(取余,取余符号两边都为整数)
++(自增),- -(自减)
3、复合运算符
+=,-=,*=,/=,%=
a += 1相当于a = a+1
a -= 1 相当于a = a-1
a *= 2 相当于a = a*2
a /= 2 相当于a = a/2
a %= 2 相当于a = a%2
四、表达式,语句
语句以分号结尾
表达式:由常量,变量,运算符组成的式子就是表达式(不以分号结尾),其中两项可以为空
五、格式化输入输出函数
输出函数语法格式:
printf(“格式串”,表达式);
格式串由转换字符和字符串组成
转换符:整型 %d
短整型 %hd
长整型 %ld
浮点型 %f
字符型 %c
字符串 %s
去掉小数点后无效0 %g
地址 %p
所占内存空间 %lu
转义字符
换行 :\n
打印% :%%
打印\ : \\
格式化输入函数
scanf(“格式串”,&表达式);
在同一个scanf内输入两个整型数,需要用空格或者逗号隔开。
格式串里面不建议加任何字符或者字符串
在同一个scanf内输入两个字符,不需要隔开
·DAY_2 C语言分支结构
一、布尔类型
bool类型:是一种非真即假(非0即真)的数据类型(不是YES,就是NO)
BOOL y = yes;
BOOL n = no;
二、关系运算符
>(大于),<(小于),>=(大于等于),<=(小于等于),!=(不等于),==(等于)
三、逻辑运算符
&&(与) 一假即假,全真即真
||(或) 一真即真,全假即假
!(非) 取反
逻辑与的短路情况
将容易为假的结果放在&&符号的左侧,效率更高
逻辑或的短路情况
将容易为真的结果放在||符号的左侧,执行效率更高
四、分支结构
if语句一般用来表示一种情况
语法格式:
if (表达式){
表达式为真执行的代码;
}
if else语句适用于两种情况的判断
语法格式:
if (表达式){
表达式为真执行此代码1;
}else{
表达式为假执行此代码2;
}
if级联式适用于多种(大于2)情况的判断
语法格式:
if (表达式1){
表达式1为真执行此语句
}else if (表达式2){
表达式2为真执行此语句
}else{
表达式1和表达式2都为假,执行此语句
}
四、条件运算符
如果式1 > 式2为真,返回式3的值,否则返回式4的值
语法格式:
表达式1 > 表达式2 ? 表达式3 : 表达式4;
五、switch case语句
语法格式
switch (整型表达式){
case 整型常量1:
如果表达式的值等于整型常量1,执行此语句1;
break;
case 整型常量2:
如果表达式的值等于整型常量2,执行此语句2;
default :
当表达式的值不等于上面任何一个常量值的时
候,执行此语句;
break;
}
break用来跳出switch语句
switch case和if else的适用环境有所区别:
switch case用于某个点的判断,更加清晰明了
if else用于某个分段的判断
六、枚举
关键字:enum
枚举:列举出所有的可能性情况
语法格式:
枚举类型关键字 枚举名{
枚举值1,
枚举值2,
……
};
枚举名可以省略
枚举值是具有符号名称的整型常量
第一个枚举值默认为0,依次递增
枚举值2设为100,不会改变之前的枚举值,但可以改变之后的枚举值
·DAY_3 C语言循环结构
循环结构定义:满足特定条件下,重复执行的语句(循环体)
一、for循环
语法格式:
for (变量的初始化; 循环条件; 循环增量) {
重复执行的语句(循环体);
}
二、随机数
产生一个随机数:[min max];
语法格式:arc4random() % (max - min + 1) + min;
三、break;continue
break用于switch语句,可以跳出switch语句。
break用在循环语句时,break后面的语句不会被执行,跳出本层循环,向下执行。
continue在循环中,continue后面的语句不会被执行,结束本次循环,向上执行。
四、循环嵌套
外层循环决定行数,内层循环决定具体实现
外层循环变化一次,内层循环变化n次(n由内部循环的循环条件决定)
五、while循环
语法格式:
while (循环条件){
循环体(重复执行的代码)
循环增量增加或减少
}
while循环通常用于不知道循环次数的情况下。
六、do while循环
语法格式:
do {
循环体(重复执行的代码语句)
}while (循环条件);
无论满不满足循环条件,都能执行一次
·DAY_4 C语言数组
一、数组
定义:相同类型的数据的集合,属于构造类型
定义语法:
数据类型 数组名[常量] = {初值1,初值2,......};
定义一个整型数组
第一种定义语法
int arr[4] = {1,2,3,4};
中括号里的4代表数组里面存放的整型数据个数为4个
第二种定义语法
int arr[4] = {1};
当初值个数少于中括号给定的元素个数,那么默认为0
第三种定义语法
int arr[] = {11,22,33};
当中括号内不给定元素个数,那么元素个数和初值个数保持一致,上面数组元素个数为3
二、数组元素的访问
访问语法:数组名[下标];
下标从0开始
可以用循环遍历数组中的每个元素
运算符:sizeof(计算所占内存空间)
格式 sizeof(表达式or类型)
求数组元素的个数
数组元素个数 = 数组所占的内存空间 / 数组中一个元素所占的内存空间
数组名是一个常量地址,数组首元素的地址
三、数组排序
冒泡排序
冒泡排序的核心思想:相邻的两个数两两比较,每一趟比较产生一个最大数,下一趟不参与比较。因此随着比较趟数的增加,每一趟比较次数减少。
语法格式
外层循环控制趟数
for(int i = 0;i < count-1;i++){
内层循环控制次数
for(int j = 0;j < count -i-1;j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
四、字符串数组
定义字符串数组第一种格式:
char arr[] = {‘a’,’d’,’d’,’c’,’c’};
第二种格式:
char arr[] = “addcc”;
char arr[5] = “12345”;(定义错误,下标越界)
字符串以 \0 结尾
字符串是字符数组,字符数组不一定是字符串
字符串用%s打印,但字符数组我们用循环%c打印
字符串四个常用的函数
求长度函数 strlen()
求字符串中有多少个字符
拷贝函数 strcpy()
将后面一个字符串拷贝给前面一个字符串
前面一个字符串的内存空间要足够容纳下后面的字符串
连接函数 strcat()
将后面一个字符串拼接到前面一个字符串上
前面一个字符串的内存空间要足够容纳下两个字符串
比较函数 strcmp()
比较两个字符串,如果前面比后面大,打印正数;相等打印0,小于打印负数。
单个单个字符比较,一旦前面的字符不等,则得出比较结果,不再比较后面的字符。
五、宏定义:直接替换
宏命名:全部大写或者驼峰命名法
#define PI 3.14
有参宏(尽量多的加括号,保证优先级)
#define SUM(A,B) ((A)+(B))
·DAY_5 C语言函数
函数:具有特定功能的代码段
一、函数定义
函数分类:库函数(main,printf...),自定义函数
自定义函数分为四种:
函数不能嵌套定义(实现)
函数定义语法(函数实现)
返回值类型 函数名(参数列表){
特定功能的代码段(函数体)
}
1、无参无返回值函数定义
void print (void){
printf (“Hello world!\n”);
}
void代表返回值为空,不能省略
print代表函数名
小括号里面代表参数列表,不写代表参数为空,因此void可以不写
大括号里是函数的特定功能实现。
函数无返回值的时候,可以给也可以不给返回值
2、无参有返回值函数定义
int max (){
return 10;
}
函数有返回值的时候,一定要用return返回值;
去掉变量名大括号,剩下来的就是函数类型
类型:无参数,有一个整型返回值的函数
3、有参无返回值函数定义
void print (int a,int b){
printf (“Hello world!\n”);
}
有两个参数,两个都是整型,无返回值的函数
定义参数类型时要一个一个定义,中间用逗号隔开
4、有参有返回值函数定义
int print (int a,int b){
return a+b;
}
函数返回a+b的值
二、函数调用
函数可以嵌套调用,但是不能嵌套实现
调用语法:函数名(参数列表);
调用规则:
1、有返回值,定义相同类型的变量来接收返回值;无返回值不用接收
2、有参数,给定相同类型的参数;无参数,可以不给参数,但是小括号不能省略
三、函数声明
函数声明即在函数定义的基础上,去掉大括号以及里面的内容加上分号
语法:返回值类型 函数名 (参数列表);
当函数定义出现在函数调用之后的时候,需要函数声明;否则,可以省略,但是一般不省略!
四、形参和实参
形参:出现在函数定义里面,称之为形参
实参:出现在函数调用里面,称之为实参
实参向形参传递参数是单向的值拷贝过程
五、函数的嵌套调用
函数可以嵌套调用,但是不能嵌套实现
·DAY_6 C语言结构体
一、声明结构体
构造类型
数组:由相同数据类型组成的一个集合
结构体:由不同数据类型组成的一个集合
struct是结构体的一个关键字
声明一个结构体类型
struct 结构体名{
数据类型 成员名1
数据类型 成员们2
数据类型 成员们3
……
};
结构体类型:struct 结构体名
二、定义结构体变量
第一种:(结构体变量定义和结构体声明分开)
语法:struct 结构体名 变量名 = {对应赋初值};
第二种:(结构体声明和结构体变量定义写在一起)
语法:struct 结构体名 {
成员变量
……
}变量名 = {对应赋初值};
三、结构体变量成员的访问
访问语法:变量名.成员名
四、为结构体类型取别名(重定义)
语法:typedef 旧名字 新名字;
五、匿名结构体
匿名结构体:没有结构体名的结构体
匿名结构体因为没有结构体名,因此定义匿名结构体变量一般直接在声明的时候就进行定义。
六、结构体所占内存空间
分配原则:自上而下分配内存空间;当上一个成员被分配的内存空间足够下一个成员适用,则下一个成员不需要分配内存;每次分配一个最大数据类型的字节空间;总字节空间为最大数据类型的整数倍
七、结构体嵌套
结构体嵌套,成员变量的成员变量访问
变量名.嵌套的结构体变量名.成员名
八、结构体数组
·DAY_7 C语言指针
内存地址:内存中的编号就是内存地址
字节是最小的存储单位
一、指针:就是地址
整型变量:用来存储整型数据的变量
指针变量(指针):用来存储地址的变量
指针的定义语法
类型修饰符 *指针名 = 初值(地址,一般给NULL);
二、指针使用
取地址符 &
p的重新赋值称为指针的重指向
int *p = &c;
取值运算符 *
*p = 20;
三、指针所占的字节数
指针所占的字节数只与操作系统位数有关,与指针类型无关
四、指针的运算:++,- -
地址只有加减,没有乘除
指针加一指加指针类型所占的字节数
五、指针变量和数组的关系
数组名是一个常量地址
数组名arr代表数组首元素地址(&arr[0])
对应关系
arr[0] p[0] *(arr+0) *(p+0)
arr[1] p[1] *(arr+1) *(p+1)
结论:去*加中括号,去中括号加*
六、数组名和指针的区别
数组所占的字节数与数组的类型以及元素个数有关
指针所占的字节数只与操作系统位数有关
七、&arr+1与&arr[0]+1
&arr+1():一次性加一个数组(arr)所占内存空间的字节数
&arr[0]+1:一次性加一个数组元素(arr[0])所占的内存空间
八、数据类型不匹配
short arr[] = {1,2,3};
读取arr[0]的低八位
char *p = arr;
int *q = arr;
九、字符数组与指针
打印字符串,只需要打印字符串对应的地址即可;
打印字符,就是对字符串取值(对字符串对应地址取值)
十、指针数组
整型数组:整型元素的集合
指针数组:指针的集合(数组里存放的是指针)
·DAY_8 C语言内存管理
一、内存区的划分
按地址从小到大分为五个区,分别是代码区,常量区,静态区(全局区),堆区,栈区。
1、代码区:用来存放代码的二进制文件,例如函数(main,sum)
2、常量区:存放常量,只可读,不可以被修改
3、静态区(全局区):静态区的变量从程序开始运行就存在,一直到程序退出才会被释放,这里的全局说的是生命周期。静态区的变量只会被初始化一次。
静态变量即static修饰的变量先于main函数执行
4、堆区:唯一一个由程序员自己申请内存,自己释放内存的区域
内存申请函数:malloc,calloc,realloc;
void*代指泛型指针,如stu*,int*,char*
内存申请函数:malloc
函数声明(函数原型):void* malloc (size_t);
对内存释放函数:free(void*)
函数声明(函数原型):void free (void*);
这里的释放指的是标记删除(释放所有权)
释放内存后的安全操作,指向空区域
int *p = malloc(8);
free(p);
p = NULL;
堆内存分配函数:calloc(size_t,size_t)
函数原型:void* calloc(size_t,size_t);
与malloc的区别:分配空间并且对被分配的内存空间按字节清零
堆内存分配函数:realloc(void *,size_t)
函数原型:void* realloc(void *,size_t);
从某一个地址开始分配size_t个内存空间
5、栈区:申请内存的模式采用先进后出,后进先出。
栈底的地址高,栈顶的地址低。
先入地址高,后入地址低。
栈区的内存空间在8M左右
栈区分配内存的测试
char str[8383240] = {0};
二、全局变量,局部变量
一个大括号看作一个作用域;在不同作用域内,变量可以重命名。
局部变量作用域其优先级别比全局变量优先级别更高
全局变量作用域更大,相对于局部变量。
·DAY_9 C语言函数指针
一、函数指针的定义:指向函数的指针
整型指针的定义:指针类型 指针变量
指针的重定向
函数名是一个地址
定义一个指针指向函数
定义一个函数指针(类型:具有两个整型参数(一个为整型数组,一个为整型))无返回值的函数指针)
void (*p)(int *,int) = NULL;
指针p是一个整型,函数sum是具有两个整型参数,一个整型返回值的函数,因此类型不匹配
int *p = NULL;p = sum;//错误
int (*p)(int ,int) = NULL;
p = sum;
通过指针名调用函数
int a = p(10,20);
二、取别名(为函数指针取别名)
为具有两个整型参数,一个整型返回值的函数指针类型取别名
在函数指针最前面加上typedef,去掉=以及右边的东西,此时指针名就成为了类型名
typedef int (*P)(int,int);
//通过别名定义函数指针
P p = NULL;
//将指针p指向sum函数
p = sum;
//通过指针调用
int a = p(10,10);
三、函数回调
第一步:用一个函数实现功能a;
第二部:将需要封装的代码拿出来作为函数b,在a的实现里进行调用;
第三步:定义一个函数指针类型和b一样,作为a的参数,将a实现体中b函数名换成指针名。
函数指针作为函数参数,函数调用时传入函数地址.