一、C语言基础复习
对部分知识点查漏补缺。
(一)C语言基本数据类型
- _Bool类型 P48
- 可移植类型:
stdint.h
和inttypes.h
P48stdin.h
提供可移植的类型名,定义了精确宽度整数类型和最快最小宽度类型。inttype.h
提供相应的输入和输出,提供字符串宏来显示可以值类型,为printf()等函数提供转换说明。
- 十六进制表示浮点型常量 P50
- 在十六进制数前加上十六进制前缀(0x或0X),用p和P分别代替e和E,用2的幂代替10的幂。
- 注意,给未在函数原型中显式说明参数类型的函数传递参数时,C编译器会把float类型的值自动转换成double类型。
(二)数组和指针
-
数组
-
初始化数组
计算数组大小时,sizeof后可直接接变量,不需要加括号。int days[] = {1, 2, 3, 4, 5}; printf("%d %d", sizeof days, sizeof days[1]);
-
-
指定初始化器
-
指定数组的大小
- 在定义数组时,必须明确确定数组的大小
- 在C99新增变长数组前,数组的大小必须是整型常量,包括由整形常量组成的表达式
-
多维数组
-
多维数组的元素按顺序存储
-
二维数组的初始化
-
可以省略行数,不能省略列数。
int arr1[4][5] = { {1, 1, 1, 1, 1}, {2, 2, 2, 2, 2}, {3, 3, 3, 3, 3}, {4, 4, 4, 4, 4}}; // 正确而完整 int arr2[4][5] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; // 正确而省略 int arr3[][5] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; // 正确而省略 int arr3[4][] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; // 错误而省略
-
-
-
数组与指针
-
指针与多维数组
-
指向多维数组的指针
声明pz为指向一个内含两个int类型值的数组:int (* pz)[2];// []的优先级高于*,应使pz为指针,然后定义其指向含两个int类型值的数组。 int arr_2d[4][2] = { { 1, 2}, { 3, 4}, { 5, 6}, { 7, 8} }; pz = arr_2d;
应注意的是,可以用数组表示法或指针表示法来表示一个数组元素。既可以使用数组名,也可以使用指针名。 例如:
arr_2d[m][n] == *(*(arr_2d + m) + n); pz[m][n] == *(*(pz + m) + n);
换言之,C把数组解释为该数组首元素的地址,数组名与指向该数组首元素的指针等价。
-
函数与数组
-
C语言不能把整个数组作为参数传递给函数,但是可以传递数组的地址,然后函数可以使用传入的地址操控原始数组。在被调函数中可以使用数组表示法或指针表示法,无论哪种表示法实际上使用的都是指针变量。
-
函数传递多维数组的方式是把数组名传递给类型匹配的指针形参。指针形参声明时需要指定除了第1个维度的所有维度,而第1个维度的带下通常作为第2个参数。声明函数的形参有两种方式:
void somefunction( int (* pz)[4], int rows); void somefunction( int pz[][4], int rows);// 第一个空的方括号表明pz是一个指针
-
-
(三)字符串和字符串函数
-
定义字符串
-
字符串字面量(字符串常量)
-
属于静态存储类别,只会被存储一次,在整个程序的生命期内存在,类似静态变量,存储在静态存储区。
-
用双括号括起来的内容被视为指向该字符串存储位置的指针。
printf("%s, %p, %c\n", "We", "are", *"space farers"); // 输出:We \, 0x100000f61, s
-
-
指针表示法
const char ar1[] = "Something."; const char * pt1[] = "Something.";
以上两个声明表明,pt1和ar1都是该字符串的地址。在这两种情况下,带双引号的字符串本身决定了预留给字符串的存储空间。
-
字符串数组形式和指针形式的区别 详见教材P277
-
程序载入内存时,字符串被载入并存储在静态存储区中。初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。 初始化完成后,指针名的地址和字符串常量相同,而数组名的地址是不同的新地址。
-
字符串数组是可修改的(除非为const),但无法通过字符串指针修改字符串常量。
-
字符串数组的元素是变量,但数组名是常量;指向字符串的指针名是变量。例如:
char arr[] = "Wow~"; char *pt = "Wow~";
两者都可以使用数组表示法,都可以进行指针加法;只有指针表示法可以递增;一般来说,只对数组表示法的字符串进行修改。
应注意的是,虽然因编译器不同有所差别,但不应该通过指针修改字符串。建议在把指针初始化为字符串常量时使用const限定符。经实测,GCC编译器中字符串常量为const类型,存储在静态存储区,不可通过指针修改。pt[0] = ’C‘;// 不推荐,实测不可行(Segmentation Fault) const char *p1 = "Wow~";// 推荐用法
-
-
-
字符串数组
方式同样有数组表示法和指针表示法。const char *sp[3] = { "Sun", "Yah", "Sen" };// 内含3个指针的数组,占用40字节。指向初始化时所用的字符串字面量的位置,字符串字面量存储在静态内存中 char sa[3][3] = { "Sun", "Yah", "Sen" };// 内含3个数组的数组,每个数组3个char类型的值,共占用9字节。数组存储了字符串字面量的副本。
比较而言,指针数组效率更高,分配的内存少,但指向的字符串字面量无法修改;如果要改变字符串或为字符串输入预留空间,应使用char类型二维数组。
- 字符串输入
- gets()函数
- fgets()函数
注意,读到换行符时,gets()会丢弃,而fgets会保留。相应地,puts()会在待输出字符串末尾添加一个换行符,而fputs()不会。 - 删除换行符与丢弃缓存区多余字符
- 字符串输出
- puts()
- fputs()
(四)存储类别、链接和内存管理
-
存储类别
- 对象是存储的值占用的一块物理内存。
- 作用域:块作用域、函数作用域、(内部链接/外部链接的)文件作用域(全局)。
- 链接:内部链接(static声明)和外部链接。
- 存储期:静态、线程、自动、动态分布。
-
分配内存:malloc()和free()
-
malloc()分配未赋名的内存,返回动态分配内存块的首字节地址。可以把该地址赋给一个指针变量,并使用指针访问这块内存。
int n; double * ptd; ptd = (double *) malloc(n * sizeof(double));// 创建动态数组
-
(五)文件输入/输出
-
标准I/O
-
检查命令行参数
-
fopen()和fclose()
-
getc()和putc()
-
文件读取范例
int ch; FILE *fp; fp = fopen("wenben.txt","r"); while (( ch = getc(fp)) != EOF) { putchar(ch); }
-
指向标准文件的指针:stdin、stdout和stderr
-
-
文件I/O:fprintf()、fscanf()、fgets()和fputs()
(六)结构和其他数据形式
-
建立结构声明
-
定义结构变量
注意,结构标记是可选的。若声明结构只用来定义一个结构变量,结构标记可以省略;若打算多次使用结构模板,则必须使用带标记的结构声明。- 初始化结构
- 访问结构成员
struct book{ char title[MAXTITL]; char author[MAXAUTL]; float value; };// 带标记“book”的结构声明 struct book library;// 定义结构变量 struct book{ char title[MAXTITL]; char author[MAXAUTL]; float value; } library;// 声明结构并定义结构变量 struct { char title[MAXTITL]; char author[MAXAUTL]; float value; } library;// 一次性声明结构并定义结构变量
-
结构数组
- 声明结构数组
- 读取结构数组
-
嵌套结构
- 传递结构成员
- 传递结构的地址
- 传递结构
struct names { char first[LEN]; char last[LEN]; }; struct student { struct names handle; char food[LEN]; char job[LEN]; float income; }; struct student fellow= { { "Mingyang", "Guo"}, "Banana", "Student", 114514.00 }; printf("%s's income is %f",fellow.handle.first,fellow.income);
-
结构/结构指针的双向通信
-
结构和结构指针的选择:传递结构指针更高效,传递结构多用于小型结构。
-
把结构内容保存到文件中【待复习】
-
链式结构
-
联合
-
枚举类型
-
typedef
- typedef为某一类型自定义名称,由编译器解释。
- typedef和#define的区别
(七)高级数据类型
- 链表
- 显示链表
- 创建链表
- 释放链表
One comment
你的文章让我感受到了正能量,非常棒! http://www.55baobei.com/P6AfNEZIQ7.html