一 C 语言知识结构
二 C 语言编码规范
三 具体知识点
1 数据类型
定义整型时默认是有符号,实型一定是有符号。
2 运算符与表达式
自增、自减:
++n 表示先执行加一操作,后使用值;n++ 表示先使用值,后执行加一操作。强制类型转换:
(float)m/2
表示把 m 先强制转换为 float 型。/(float)(m/2)
把 m/2 的结果强制转换为 float 型。
3 键盘输入、屏幕输出
单个字符输入输出:
a)ch = getchar()
,无参数,赋给变量 ch。/getchar()
以回车为结束符,会将结束符留在缓冲中。
b)putchar(ch)
,参数为要输出的字符变量;参数可以为变量、ASCII 数值、字符本身(记得加单引号)。字符串输入输出:
a)gets(str)
,输入的字符赋给数组 str。/gets(str)
以回车为结束符,不留在缓冲中。
b)puts(str)
,参数为数组 str、字符串本身(记得加双引号)。格式化输入输出:
a)scanf("%2d%*c%2d",&a,&b)
,表示连读两个数字(数字表示截取的宽度)当成一个变量值,忽略掉一个任意字符,最后再截取两个宽度的数字。/ 一般在 scanf() 函数后加一个 getchar() 函数,或下一行的 scanf() 函数中加个空格。/scanf()
以回车、空格、Tab 为结束符,会将结束符留在缓冲中。
b)printf("%-5.2f",num)
,表示变量 num 的浮点数在列宽为 5 的长度内左靠齐,小数点后保留 2 位(小数点也算一列),如果为字符串则表示左开始截取的字符数。补充:在用
%c
格式读入字符时,空格、转义、回车都会当作有效字符读入。
4 控制结构
顺序:
略。选择:
双分支、多分支:
1
2
3
4
5
6
7
8
9
10
11
12if()
{
...;
}
else if()
{
...;
}
else
{
...;
}条件运算符:
max = a > b ? a : b
,表示前面的为非 0,取 a 值,否则取 b 值。多路选择语句:
1
2
3
4
5
6
7
8
9
10
11switch(x)
{
case 常量:
...;
break;
case 常量:
...;
break;
default:
...;
}
- 循环:
while 循环:
1
2
3
4while()
{
...; // 条件为真循环
}do while 循环:
1
2
3
4do
{
...; // 条件为真循环
}while();for 循环:
1
2
3
4for(初始化表达式; 循环控制表达式; 增值表达式)
{
...;
}
5 函数
函数的定义:
1
2
3
4返回值类型 函数名(类型 形参1, 类型 形参2, ...)
{
...;
}传递参数:
按值调用:实参为变量名,形参为变量名。/ 是传一个副本给函数。
按地址调用:实参为地址,形参为指针变量。/ 函数通过指针解引用访问原本变量。变量的作用域、存储类型:
6 数组
定义一、二维数组:
1
2
3
4类型 数组名 [第一维长度]
类型 数组名 [第一维长度][第二维长度]
// 二维数组定义时必须知道列元素向函数传递数组:
直接传递数组名。函数形参:
1
2
3
4
5
6
7
8
9int function(a[], n)
{
... // 一维数组可以不指定长度,用参数 n 来表示
}
int function(a[][8])
{
...
}
7 指针
指针变量就是存储地址的变量,声明时为
int *p = &a;
,引用变量 a 的值需要先指针解引用b = *p
(此时用星号来引用该存储的地址的变量的值)。/ 指针类型的大小是固定的。%p
为输出地址值的格式控制;&
为取地址符。输出变量地址值:1
2
3
4int a = 2;
int *pzz = &a;
printf("address is %p",pzz);
printf("address is %p",&a);函数指针:
指向函数的指针,存的是函数在内存中的入口地址,函数指针如int (*compare)(int a, int b)
。实参是函数名,形参是函数指针。指针函数:
函数返回的是一个指针,如int *compare(int a, int b)
。指针小结:
a)指针数组存放的是指针数组(若干个指针变量)变量自己的首地址(是数组、指针两个概念的集合)。/ 指针数组名 + n 来表示组中若干个指针变量;注意,数组名相当于首地址指针常量,不能加法移动改变位置。
b)数组和指针类似,不同之处:数组名存放的是数组变量自己的首地址;指针存放的是其它变量的地址。
c)基本类型变量存放的是一个数据值。
d)字符串数组既类似基本变量(可以直接通过数组地址引用值,常用方法)、也是数组。
8 字符串
C 语言没有字符串类型,所以用数组间接实现。
字符串常量用
""
引号包含,编译器在结尾自动加一个\0
表示是字符串。初始化:
1
2
3
4
5char str[] = "hello";
char str[] = {'h','e','l','l','o','\0'};
char weekday[][10] = {"sunday","monday",...}; // 没填满的地方全自动加上 \0字符指针:
每个字符串常量在内存中占用一段连续的空间,有唯一确定的首地址。字符串常量本身代表存放它位置的首地址,此时不能对其内容修改。要修改则需要用数组赋值字符串。1
2
3
4char *ptr = "hello";
等价于
char *ptr;
ptr = "hello";访问时注意:不能用数组名自加
str ++
,因为数组名是一个地址常量;可以用指针自加,如ptr ++
。引用第某个字符:*(ptr + i)
、*(str + i)
即str[i]
。字符串的输入输出:
scanf() 函数按%c
一个一个字符输入输出,用循环遍历存字符串的数组单元。/ 循环输出,条件为不是结束符\0
。
scanf() 函数按%s
存入数组名 str。
使用字符串处理函数输入输出,如gets(str)
、puts(str)
,str 为数组名。一些字符串处理函数:
1
2
3
4
5
6
7
8strlen(str); // 实际长度,不含 \0
strcpy(str1,str2); // 将 str2 复制到 str1
strcmp(str1,str2); // 从左到右逐一比较其 ASCII 值,直到遇见不同字符或结束。str1 大于 str2 返回值大于 0;等于、小于同理。
strcat(str1,str2); // 将 str2 放入 str1 末尾(覆盖掉 str1 的结束符)
strncpy(str1,str2,n); // 最多 n 个字符
strncmp(str1,str2,n);
strncat(str1,str2,n);向函数传递字符串:
可用字符数组做函数参数(实参是数组名),也可用字符指针做函数参数(实参是数组名)。关于 const 类型限定符:
9 指针与数组
数组作为函数形参和指针一样,因为实参数组名本质上传递的都是地址(地址调用,非值调用)。
二维数组:二维数组是由若干个一维数组构成的。
二维数组的指针定义、初始化:
1
2
3
4
5
6
7
8
9行指针:使用二维数组的行地址初始化。
定义:int (*p)[4]; // 表示指向一维数组的指针,有 4 个元素;指向二维数组的指针,每行有 4 个元素。
初始化:p = a; 或 p = &a[0];
元素引用:a[i][j] 等价 *(a[i]+j) 等价 *(*(a+i)+j) 等价 (*(a+i))[j]
列指针:使用二维数组的列地址初始化。
定义:int *p;
初始化:p = a[0] 等价 p = *a 等价 p = &a[0][0]
元素引用:a[i][j] 等价 *(p+i*n+j) 等价 p[i*n+j]指针数组:
指针数组的每个元素都是指针(涉及字符串操作用指针数组比用二维数组更有效)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17e.g.
char *pstr[N] = {"hello","world","ni","hao"};
e.g.
int main(void) {
char *people[3];
int i;
for(i=0;i<3;i++)
{
people[i] = (char *)malloc(10 * sizeof(char)); // 每个元素是一个指针(存储名字的数组首地址)
printf("enter name:\n");
gets(people[i]); // 输入第 i 个字符串(名字)到 people[i] 指向的内存(存名字的数组)
printf("\n");
}
printf("the name are:%s,%s,%s.",people[0],people[1],people[2]);
return 0;
}用指针数组接收命令行参数:
1
2
3
4
5
6int main(int argc,char *argv[]) // argc argv 是惯例取名
{
...; // int argc 用于存放命令行中参数个数(至少为 1,函数名也是参数)
// char *argv[] 用于接收命令行参数
// 程序不需要命令行参数就写 void
}动态数组:
1
2
3
4
5
6
7
8
9
10
11函数 malloc(size)
void *malloc(unsigned int size);
e.g.
int *pi = NULL;
pi = (int *)malloc(5); // 申请 5 个字节空间,强制转换成 int 型指针
函数 calloc(n,size)
void *malloc(unsigned int num,unsiged int size); // 若干个 n 字节空间,并初始化为 0,相当于一维数组
函数 realloc(p,size)
void *realloc(void *p,unsiged int size); // 指针 p 指向的空间重新分配空间,返回新分配的空间地址。与原来的地址不一定相同。补充一些函数:
free() 函数:void free(void *p);
,与 mallco() 函数成对使用。
exit() 函数:exit(1) 异常退出,exit(0) 正常退出。
10 结构体、共用体
结构体定义:
1
2
3
4
5typedef struct student
{
...;
...;
} STUDENT; // 直接定义为 STUDENT 类型结构体变量初始化:
1
2
3
4
5
6
7STUDENT stu1 = {10002,"ZhangSan",'M'};
或者用圆点运算符引用结构体变量成员赋值
(注意:
字符串数组需要用 strcpy() 函数赋值,不能直接赋值;
如果是数组的话,scanf() 输入时不用加 & 取地址符号,如 scanf("%s",&stu1.studentid);
)。关于结构体指针:
结构体变量的地址作为实参,传递到函数(形参为指针变量)。此时在函数内引用结构体变量的成员,直接写成w->name
相当于(*w).name
(指针的解引用)。/ 圆点.
用来引用结构体变量成员,箭头->
用来在结构体指针引用成员。共用体:
使用覆盖技术,需要使几种不同类型的变量存放到同一段内存单元中,成为共同体类型的结构。
共用体大小取决于占用空间最大的成员。每一瞬时起作用的就是最后被赋值的成员,只能对一个成员初始化。
不能引用共用体变量,而只能引用共用体变量中的成员。1
2
3
4
5
6
7
8
9
10union sample
{
short i;
char ch;
float f;
};
引用:
union sample a;
printf("%d", a.i);枚举类型:
有限个数据组成的量,用枚举类型来表示。花括号内是枚举变量可能的取值。1
2
3
4
5
6
7
8
9enum response {no = -1,yes = 1,none = 0}; // 可以定义时赋值,如果第一个赋值 1,后面的会递增
enum response answer;
e.g.
if(answer == yes)
{
...;
}
11 文件操作
- 参考博文:C 语言文件操作完全攻略