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)

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
===========

指针在子函数中的使用:

#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 的对象)

#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
===========

结构体初始化两种方式:

方式一: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 类型,可以接纳所有类型

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

静态局部变量和全局变量很像,可以累加使用,唯一的不同就是静态局部变量还是局部方法里面使用,全局是整个程序使用。

#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 函数的返回类型!

 

 函数指针数组:

 * 堆的动态申请和释放

* 越界:

 

posted @ 2022-02-13 11:39  雪化山河  阅读(166)  评论(0)    收藏  举报