C语言知识总结
* 各个类型的变量输出的方式:
double float 用 %f ,char 用 %c(打印字符) 和 %d(打印编码),int 用 %d,字符串用 %s,指针用 %p 打印
* 定义变量不初始化,直接使用,并不会报错,结果输出这个变量是随机的。
* 定义数组不初始化,分两种情况,有加 { } ,输出的值初始化默认是 0 ,而不是随机的;没加 { } ,则是随机的:
a[3] = {1,2,3} //完全初始化
a[3] = {}; //不完全初始化
a[3] = {1}; //不完全初始化
a[3]; //无初始化
a[3] = {[0] = 1,[2] = 100}; //gcc 特有的初始化 ,指定位置数据
a[3] = {1,[2] = 100}; //gcc 特有的初始化 ,指定位置数据
这样定义数组,输出为:
0 0 0
1 0 0
随机 随机 随机
1 0 100
1 0 100
============================================================================
指针:
(1)
int a = 11; //定义 int 类型变量为 a
int *p ; //定义一个“指针类型”变量为 p,指向 int 类型数据(指针本身是一种类型)【可以写成:int * p 、int* p 都可以】
p = &a; // & 表示内存地址,这里表示把 a 的内存地址赋值给指针 p
*p = 22; //给指针类型p 赋值为 22
输出 a 等于:
22 //最终就相当于修改了a的内存地址的值为 22
(2)
int a[5] = {55,44,33,22,11};
int *p;
----
p = &a; //编译警告,但执行结果正确,打印 55【数组类型不能直接赋值给int类型的指针】
p = &a[0]; //编译正常,执行正常,打印 55【这样表示“数据首元素”的首地址,意思和下面不同,但是值一样】
p = a; //编译正常,执行正常,打印 55【对于数组来说,直接使用变量 a,表示的是“整个数组的首地址”,和上面意思不一样,但是打印值一样】
----
数组的两种表示方式,利用指针也可以来表示数组:
例如有:
int a[5] = {55,44,33,22,11};
int *p;
p = a;
依次输出:
第一种:a[0] a[1] a[2] a[3] a[4]
第二种:*p *(p+1) *(p+2) *(p+3) *(p+4)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void main() { printf( "===========\n" ); int a[5] = {11,22,33,44,55}; int *p; p = a; for ( int i=0;i<5;i++){ printf( "*p = %d \n" ,*(p+i)); } printf( "===========" ); } 打印出: =========== *p = 11 *p = 22 *p = 33 *p = 44 *p = 55 =========== |
指针在子函数中的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <stdio.h> int exchange1( int a, int b); int exchange2( int *a, int *b); void main() { printf( "===========\n" ); int x = 3,y = 5; printf( "begin param x = %d,y=%d\n" ,x,y); //exchange1(x,y); exchange2(&x,&y); printf( "begin param x = %d,y=%d\n" ,x,y); printf( "===========" ); } int exchange1( int a, int b){ int t; t = a; a = b; b = t; return 0; } int exchange2( int *a, int *b){ int t; t = *a; *a = *b; *b = t; return 0; } //调用 exchange1 输出: =========== begin param x = 3,y=5 begin param x = 3,y=5 =========== //调用 exchange2 输出: =========== begin param x = 3,y=5 begin param x = 5,y=3 =========== |
结构体:(就类似 java 的对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <stdio.h> //定义一个结构体,struct 是关键字 struct User{ char name[20]; //姓名 int num; //编号 int sex; //性别 }; void main( void ) { printf( "===========\n" ); struct User s; s.name[0] = 'M' ; s.name[1] = 'o' ; s.name[2] = 'n' ; s.name[3] = 'g' ; s.name[4] = 'o' ; s.num = 38; s.sex = 1; //字符输出用 %s printf( "name = %s,num = %d,sex = %d\n" ,s.name,s.num,s.sex); printf( "===========" ); } 输出: =========== name = Mongo,num = 38,sex = 1 =========== |
结构体初始化两种方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 方式一:struct User u = {x1,x2,x3,x4,x5}; 方式二:struct User u = { .a = x1, //用逗号隔开,a前面的点不可省略 .b = x2, .c = x3, .d = x4, .e = x5 }; //最后的分号不可省略 |
* 共生体(类似 java 的父类)
============================================================================
* 宏定义 ://类似 java 的全局常量,命名全大写,下划线连接
#define NUM (10) //数据要用括号包起来
#define SUM_NUM (NUM+10) //后定义的可以使用上面先定义的,结合使用
//例子,使用宏定义表示一年的秒数
#define YEAR_SECOND (365*24*60*60)UL //UL 表示强制赋值,不然默认为 int 类型,超出长度了,也可以简写成 U【UL 表示无符号类型】
============================================================================
* 枚举
enum week{
SUN,
MON,
TUE,
WEN,
THU,
FRI,
SAT
}
============================================================================
* void 用法,类似 java 里面的 Object 类型,可以接纳所有类型
1 2 3 4 5 6 7 8 9 10 11 12 | void main( void ) { printf( "===========\n" ); int a = 123; void *p; //定义 void 类型的指针 p = &a; printf( "*p = %d\n" ,*( int *)p); //正确 printf( "*p = %f\n" ,*( float *)p); //错误 printf( "===========" ); } |
* C语言没有 bool 类型(C++ 有),需要使用的时候,用 int 代替,在C语言中,除了 0 ,其余正负 int 数据,都是 1
* 全局变量和局部变量
只是定义没有初始化的情况下,局部变量每次数据是“随机值”,全局变量默认是 0
静态局部变量和全局变量很像,可以累加使用,唯一的不同就是静态局部变量还是局部方法里面使用,全局是整个程序使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include <stdio.h> void fun1(); void fun2(); void main( void ) { printf( "===========\n" ); fun1(); fun1(); fun1(); printf( "-----------\n" ); fun2(); fun2(); fun2(); printf( "============" ); } void fun1(){ int a = 1; a++; printf( "a = %d\n" ,a); } void fun2(){ static int b = 1; //静态局部变量,只初始化一次,后续不再初始化 b++; printf( "b = %d\n" ,b); } 输出: =========== a = 2 a = 2 a = 2 ----------- b = 2 b = 3 b = 4 ============ |
* 多文件的相互调用:
比如:a.c 和 b.c 有两个文件,在编译的时候,使用命令:gcc a.c b.c -o ab 即可把两个文件关联成一个项目。
如果两者之前的函数,变量要相互调用,必须在顶部声明:
(1)对于函数,和单独一个文件的声明方式一样,直接声明即可。【两个文件不能出现一样的函数名字】
(2)对于变量(只有全局变量),有两种方式来使用,
①间接使用,比如 a.c 文件中一个函数 fun 调用了,在 b.c 文件中调用函数 fun 即可间接使用该变量
②使用关键字:extern 来声明,比如:
a.c 文件中有一个全局变量 :int g_a = 11;
b.c 文件中要使用,则这样声明:extern int g_a; //不可再赋值
* 静态全局变量的理解:
普通全局变量,是整个项目都可以使用的,一旦定义,即使不同文件之前也不能再出现重名的;
静态全局变量,就是规定只在我当前这个文件中可以使用,另外的文件不可以使用。
* 常量(不会改变的值)
方式:
①宏定义就是一种常量的表现形式
②使用关键字:const 定义。例如:const int a = 1;
“常量”和“指针”结合的重点理解:
const int *p; //p是一个指针,指针指向一个int类型的数据。p所指向的是一个常量
int const *p; //p是一个指针,指针指向一个int类型的数据。p所指向的是一个常量
int *const p; //p是一个指针,指针指向一个int类型的数据。p本身是常量,p所指向的是一个变量
const int *const p; //p是一个指针,指针指向一个int类型的数据。p本身是常量,p所指向的也是一个常量
* 回调函数:把整个函数当作参数传给另一个函数使用,需要用到指针来配合。
使用场景:当 A 函数的执行时间需要由 B 函数来决定时,可以把 A 函数当作参数,整个传给 B 函数,然后由 B 来执行。
返回函数指针:
注意: typedef int (*opFunc)(int,int) 中 typedef 后面的 int 类型,取决于 add 和 sub 函数的返回类型!
函数指针数组:
* 堆的动态申请和释放
* 越界:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通