基础:
1、在c语言里面C99标准里面有32个关键字
2、for循环的执行流程:for(int i=0;i<size;i++)
{}
流程: int i --->i<size---->{}---->i++
3、goto语句仅能够在函数体的内部进行跳转。
4、什么是数组?
概念:相同元素在内存里面 的集合
分类:一维数组和多维数组
特性:底层是连续的空间、支持随机访问(sizeof(数组名) = 整个数组的大小)
用法:1、存储数据元素
2、最为函数的参数进行传参
3、作为函数的返回值
5、函数:概念:在程序里面由一个或者多个语句块组成的子程序。
分类:库函数-->完成有限的功能、在使用的时候必须包含#include和对应的头文件
自定义函数--->可以自己定义想要的逻辑功能
函数的参数:实参-->正真传给函数的参数(可以是常量、变量、表达式、函数等)
形参-->形式参数是指函数部分的参数,因为函数参数部分的参数只有在函数被调用的过程中才会被实例化,所以叫形式参数,
形式参数在函数调用完成之后会自动销毁,因此,形式参数只有在函数类里面才有效
函数设计注意事项:1、函数的参数不要过多
2、函数设计要注意代码的复用性
3、函数参数和返回值要满足功能的需要
函数传参:1、传值---->形参是实参的一份拷贝
2、传址---->形参是实参地址的一份拷贝
3、传引用---->形参是实参地址的一份拷贝(C++)
函数返回值方式:1、通过寄存器返回
2、栈返回--->当返回的数据过多的时候,不能通过寄存器返回,返回栈时-->先Push一个地址--->将返回数据存储到这个地址的内存里面---->返回这个指针
进阶:
1、生成可执行程序的过程:
预处理------------->编译------------------>汇编----------------------->exe
预处理:1、预定义符号__FILE__ //进行编译的源文件
__LINE__ //文件当前行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
2、#define定义宏:在定义宏的时候尽量将想要表达的顺序的变量之间加上()
宏是和类型无关的--->在预处理阶段直接替换---速度快
没有类型检查----不安全
宏和函数的对比:
条件编译:解决头文件重复包含的问题
常见的预处理条件编译指令:#if 常量表达式
........
#endif
#ifndef 表达式
#define 表达式
.......
#endif
2、C/C++里面的内存分配
栈区(系统自己分配释放):局部变量、函数参数、返回值、返回地址等。
堆区(程序员分配释放):mallo、new分配的内存
全局区(静态区):全局变量、静态数据、常量。程序结束后系统释放
文字常量区:常量字符串。程序结束后系统释放。
程序代码区:存放函数体(类的成员函数和全局函数)的二进制代码。
内存分配的方式:1、从静态存储区分配---->全局变量、static变量
2、在栈上开辟空间--->执行函数,函数体内的局部变量
3、从堆上开辟空间---->malloc,new
volatile关键字:编译时候不优化、执行的时候不缓存,每次都在内存里面读取(保证内存的可见性)
3、函数进阶理解
函数栈帧:
函数的递归:递归的条件:1、存在限制条件,当这个限制条件满足的时候,递归继续,如果不满足的话就结束递归。
2、每次递归都应该向限制条件靠近。
递归示例:菲波那切数列
main函数的参数解析:main函数的原型 int main(int argc,char *argv[],char *envp[]){}
第一个参数:argc是整形变量,表示命令行参数的个数。
第二个参数:argv是一个字符指针数组,每个元素都是字符指针。
地三个参数:envp是字符指针数组,每一个元素指向一个环境变量字符串的指针。
可变参数列表:(函数参数不确定的函数)
示例:#include<stdio.h>
#include<stdarg.h>
int Add(int n,...)
{
va_list arg;
int i =
0;
int sum =
0;
va_start(arg,n);
for (;i<n;i++)
{
sum += va_arg(arg,int);
}
return sum;
va_end(arg);
}
int main()
{
int a =
10;
int b =
20;
int c =
15;
int sum1 = Add(2,a,b);
int sum2 = Add(3,a,b,c);
printf("%d\n",sum1);
printf("%d\n",sum2);
return 0;
}
- 声明一个va_list类型的变量arg,这个变量用来访问参数列表里面未确定的部分
- va_list声明的变量用va_start来初始化,他的第一个参数是va_list的变量va_list的变量名,第二个参数是省略号前最后一个有名字的参数。初始化过程吧arg变量设置成可变参数列表部分的第一个参数。
- va_arg这个宏接受两个参数,va_list变量的变量和参数列表中的下一个参数类型
- 最后需要在访问完毕之后调用va_end。
注意:
- 可变参数列表里面必须从头到尾逐个访问,可以中途停止但是不可以开始就访问参数列表里面的中间元素。
- 参数列表里面必须至少有一个明名参数,否则无法使用va_start
- 这些宏是不对参数类型进行类型检测的
- 如果在va_arg里面出现错误,那么在程序里面后果是不可以预测的。
3、指针
概念:用来存储地址的变量单元
注:指针的类型决定指针向前或者向后走一步有多大的距离
模拟实现:strlen、strcat、strstr、strcpy、strcmp...
重点------>C语言课件指针下
//代码1
(*(void (*)())0)();
//调用一个将0强转成void (*)()类型的函数
//代码2
void (*signal(int , void(*)(int)))(int);
//声明一个返回值类型为void (int )类型,参数为int和void (*)(int)型指针的函数指针。
示例:函数指针实现一个通用的计算器
4、结构体
概念:将一些具有共同特征(属性)的变量封装在一起,组成的自定义数据类型。
结构体对齐规则:1、成员对齐:min(默认对齐数,成员类型)
2、整体对齐:min(默认对齐数,max成员类型)*n
结构体里面如何求一个成员变量相对于结构体其实位置的偏移量?
offsetof(结构体类型,成员名)
offsetof(s,m) *(size_t)&((s*)0->m);
5、文件操作
fopen(文件路径,打开模式);
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
fseek(文件指针,偏移量,起始点);
fgetc(文件指针)从文件指针里面读入一个字符
fputc(str,fp)将str里面的字符写到fp里面去。
fgets(str,n,fp)从fp里面读入长度为n的字符串到str里面去。
fputs(str,fp)将str里面的字符串写到fp里面去。