好的,我们来系统地复习一下《C程序设计语言(第二版)》(即ANSI C版本)的核心知识点。这本书由C语言之父Dennis Ritchie和Brian Kernighan编写,是学习C语言的圣经。
我们将按照书籍的大致结构,分为以下几个核心部分进行复习:
#include <stdio.h> // 预处理指令,包含标准输入输出库
int main() { // 主函数,程序入口
printf("hello, world\n"); // 输出语句
return 0; // 返回值,0表示成功
}
源文件 (.c) -> 编译器 -> 目标文件 (.o/.obj) -> 链接器 -> 可执行文件 (.exe/.out)
main()
函数是必须的,int main(void)
或 int main(int argc, char *argv[])
是标准形式。int
:整型float
, double
:浮点型char
:字符型short
, long
:修饰整型,如 long int
signed
, unsigned
:指定符号性123
, 0x1F
(十六进制), 017
(八进制)3.14
, .2
, 1e-5
'a'
, '\n'
(转义字符)"Hello"
const
关键字或 #define
宏定义常量。+
, -
, *
, /
, %
(取模)<
, <=
, >
, >=
, ==
, !=
&&
(与), ||
(或), !
(非)&
(按位与), |
(按位或), ^
(按位异或), ~
(按位取反), <<
(左移), >>
(右移)=
, +=
, -=
, *=
, /=
, %=
, &=
, |=
, ^=
, <<=
, >>=
++i
, i++
, --i
, i--
expr1 ? expr2 : expr3
expr1, expr2
if (condition) statement
if (condition) statement else statement
switch (expression) { case const-expr: statements; ... default: statements; }
while (condition) statement
for (expr1; expr2; expr3) statement
(expr1
初始化,expr2
条件,expr3
增量)do statement while (condition);
(至少执行一次)break;
:跳出循环或switch。continue;
:跳过本次循环剩余部分。goto label;
:跳转到标签(慎用)。return expression;
:从函数返回。// 函数声明(原型)
int max(int a, int b);
// 函数定义
int max(int a, int b) {
return a > b ? a : b;
}
// 调用
int result = max(10, 20);
void
无返回)。extern
跨文件访问)。static
#include <stdio.h>
(系统头文件)或 #include "myheader.h"
(用户头文件)#define PI 3.14159
(定义常量)#define SQUARE(x) ((x) * (x))
(带参宏,注意括号避免优先级问题)#if
, #ifdef
, #ifndef
, #else
, #elif
, #endif
#ifndef MYHEADER_H
#define MYHEADER_H
/* 头文件内容 */
#endif
int *p;
(指向int的指针)&
,如 p = &i;
*
,如 j = *p;
(获取p指向的值)p + n
前进 n * sizeof(type)
字节)。==
, !=
, <
, >
等(通常用于同一数组内)。int arr[10];
arr
等价于 &arr[0]
)。arr[i]
等价于 *(arr + i)
。int matrix[3][4];
matrix[i][j]
等价于 *(*(matrix + i) + j)
。int arr[]
等价于 int *arr
)。'\0'
结尾的字符数组。<string.h>
):
strlen(s)
:返回长度(不包括'\0'
)。strcpy(dest, src)
:复制字符串。strcat(dest, src)
:连接字符串。strcmp(s1, s2)
:比较字符串。"hello"
是一个只读的字符数组(类型为 const char[]
),切勿修改。int *arr[10];
(数组元素是指针)int (*arr)[10];
(指向长度为10的数组的指针)int (*pf)(int, int);
(指向返回int,参数为两个int的函数的指针)pf = max;
(*pf)(a, b)
或 pf(a, b)
const
与指针:
const int *p;
:指向常量的指针(不能通过p修改所指内容)。int *const p;
:常量指针(指针本身不可变)。const int *const p;
:指向常量的常量指针。// 声明变量 struct point p1 = {1, 2}; struct point p2 = {.y=2, .x=1}; // C99指定初始化器
// 通过指针访问成员 struct point pp = &p1; (pp).x = 10; pp->x = 10; // 等价写法
- 结构体可以嵌套,可以包含数组、指针甚至其他结构体。
- 结构体大小可能包含填充字节(内存对齐)。
#### 2. 联合 (union)
- 所有成员共享同一块内存(大小由最大成员决定)。
```c
union data {
int i;
float f;
char str[20];
};
enum color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2
enum color c = RED;
malloc(size_t size)
:分配指定字节数的内存,返回void*
(需要类型转换)。calloc(size_t nmemb, size_t size)
:分配数组(初始化为0)。realloc(void *ptr, size_t size)
:调整已分配内存的大小。free(void *ptr)
:释放内存。int *arr = (int*)malloc(10 * sizeof(int));
if (arr == NULL) {
// 处理分配失败
}
// 使用...
free(arr);
arr = NULL; // 避免野指针
NULL
,防止内存泄漏(分配后必须释放)。printf(format, ...)
:格式化输出。
%d
, %f
, %c
, %s
, %p
, %x
等。scanf(format, ...)
:格式化输入。
&变量
),字符串数组名不用(因为是指针)。getchar()
, putchar(c)
:字符输入输出。FILE *fp;
fopen(filename, mode)
"r"
(读),"w"
(写),"a"
(追加),"r+"
(读写)等。fclose(fp)
getc(fp)
, putc(c, fp)
fgets(buf, size, fp)
, fputs(buf, fp)
fprintf(fp, format, ...)
, fscanf(fp, format, ...)
fread(ptr, size, nmemb, fp)
, fwrite(ptr, size, nmemb, fp)
fseek(fp, offset, whence)
(SEEK_SET
, SEEK_CUR
, SEEK_END
),ftell(fp)
,rewind(fp)
feof(fp)
(检查文件结束),ferror(fp)
(检查错误)。<stdarg.h>
中的宏:
va_list
:声明参数列表变量。va_start(ap, last_fixed_param)
:初始化。va_arg(ap, type)
:获取下一个参数。va_end(ap)
:清理。printf
)。<stdio.h>
:输入输出。<stdlib.h>
:动态内存、随机数等。<string.h>
:字符串处理。<math.h>
:数学函数。<ctype.h>
:字符分类。<time.h>
:时间日期。char *s = "hello"; s[0] = 'H';
(错误!)。#define SQUARE(x) x*x
,SQUARE(i++)
会递增两次。==
判断浮点数相等:应使用精度判断(fabs(a - b) < epsilon
)。要牢固掌握ANSI C,必须理解:
最好的复习方法是结合实践:
gcc -Wall -g
编译,使用 gdb
调试,使用 valgrind
检查内存错误。