《C程序设计教程(修订版)》学习指南
本指南将按照一个典型的C语言教程结构,分为几个核心模块,每个模块都包含核心概念、关键知识点、常见陷阱和示例代码,并提供了进阶学习的建议。

C语言入门基础
这是您踏入C语言世界的第一步,目标是理解C语言是什么,以及如何编写最简单的程序。
核心概念
- C语言的特点:结构化语言、高效、可移植、接近硬件。
- 程序的基本结构:一个C程序由一个或多个函数组成,
main()函数是程序的入口点。 - 编译与执行:理解源代码 (
.c) -> 编译 (生成.obj或.o) -> 链接 (生成.exe) -> 运行的过程。
关键知识点
#include <stdio.h>:告诉编译器包含标准输入输出库,以便使用printf()和scanf()等函数。int main():程序的起始函数。int表示函数执行完毕后会返回一个整数值给操作系统(return 0;表示成功)。printf():格式化输出函数,学习常用的格式控制符:%d:整数%f:浮点数%c:字符%s:字符串
scanf():格式化输入函数。特别注意:在%d等格式符前最好加上一个空格" %d",以跳过输入中的空白字符(如回车、空格)。- 注释: 单行注释 和 多行注释,良好的注释是代码可读性的关键。
示例代码
// 文件名: hello.c
#include <stdio.h>
// main函数是程序的入口
int main() {
// 使用printf函数在屏幕上打印信息
printf("Hello, World!\n"); // \n 是换行符
// 声明一个整型变量
int age;
// 提示用户输入
printf("Please enter your age: ");
// 读取用户输入并存储到age变量中
scanf("%d", &age); // &age 表示age变量的内存地址
// 输出用户输入的内容
printf("You are %d years old.\n", age);
// 程序正常结束,返回0
return 0;
}
常见陷阱
- 忘记
#include <stdio.h>:导致printf和scanf未定义。 main函数拼写错误:如写成mian。printf或scanf中忘记格式控制符:如printf(age),正确应为printf("%d", age)。scanf中忘记取地址符&:如scanf("%d", age),正确应为scanf("%d", &age)。
数据类型、运算符与表达式
这是C语言的基石,定义了程序处理的数据和操作方式。
核心概念
- 变量:内存中一个命名的存储位置,用于存放数据。
- 常量:程序运行期间其值不能改变的量。
- 数据类型:规定了变量可以存储的数据种类和大小(如整数、小数、字符)。
- 表达式:由变量、常量、运算符组成的式子,计算后会产生一个结果。
关键知识点
- 基本数据类型:
int:整数,通常占4字节。float:单精度浮点数(小数),占4字节。double:双精度浮点数,占8字节,精度更高。char:字符,占1字节。
- 类型转换:
- 自动类型转换:当不同类型数据运算时,系统会自动将低精度类型转换为高精度类型(如
int+double->double)。 - 强制类型转换:使用
(类型名)运算符,如(int)3.14结果为3。
- 自动类型转换:当不同类型数据运算时,系统会自动将低精度类型转换为高精度类型(如
- 运算符:
- 算术运算符:, , , , (取模,求余数)。
- 关系运算符:
>,<,>=,<=, (等于),(不等于)。注意: 用于判断是否相等, 用于赋值。 - 逻辑运算符:
&&(与),(或),(非),常用于if条件判断。 - 赋值运算符:, , 等。
示例代码
#include <stdio.h>
int main() {
int a = 10, b = 3;
float c = 3.14f; // f后缀表示float类型
double d = 9.8;
char ch = 'A';
// 算术运算
printf("a + b = %d\n", a + b); // 13
printf("a / b = %d\n", a / b); // 3 (整数除法,小数部分被舍弃)
printf("a %% b = %d\n", a % b); // 1 (取模)
// 类型转换
printf("(int)c = %d\n", (int)c); // 3
// 关系和逻辑运算
if (a > b && ch == 'A') {
printf("a is greater than b and ch is A.\n");
}
return 0;
}
流程控制
让程序根据不同条件执行不同操作,或者重复执行某些操作,这是程序智能化的体现。
核心概念
- 顺序结构:代码从上到下依次执行。
- 选择结构:根据条件判断,选择执行不同的代码块。
- 循环结构:重复执行某段代码,直到条件不满足为止。
关键知识点
if-else语句:最基本的选择结构。if (条件) { // 条件为真时执行 } else { // 条件为假时执行 }switch语句:多分支选择,适用于判断一个变量的值是否等于几个常量之一。switch (表达式) { case 常量1: ... break; case 常量2: ... break; default: ... break; }for循环:循环次数已知时最常用。for (初始化; 条件判断; 循环后操作) { // 循环体 }while循环:循环次数未知,但循环条件明确。while (条件) { // 循环体 }do-while循环:至少执行一次循环体,然后再判断条件。do { // 循环体 } while (条件);break和continue:break:立即跳出当前循环或switch语句。continue:跳过本次循环的剩余部分,直接进入下一次循环。
示例代码(打印九九乘法表)
#include <stdio.h>
int main() {
int i, j;
// 使用嵌套for循环
for (i = 1; i <= 9; i++) {
for (j = 1; j <= i; j++) {
printf("%d*%d=%-2d ", j, i, i * j); // %-2d 左对齐,占2位
}
printf("\n"); // 每行结束后换行
}
return 0;
}
函数
将复杂问题分解为小的、可管理的单元,是模块化编程的核心。

核心概念
- 函数的定义:指定函数名、返回值类型、参数列表和函数体。
- 函数的调用:使用函数名并传递实际参数来执行函数。
- 参数传递:C语言中,函数参数传递是“值传递”,即传递的是值的副本。
关键知识点
- 函数定义格式:
返回值类型 函数名(数据类型 参数1, 数据类型 参数2, ...) { // 函数体 return 返回值; // 如果返回值类型是void,则可以省略return或return; } - 声明与定义:函数声明(原型)告诉编译器函数的存在和接口,通常放在文件开头,函数定义是函数的具体实现。
- 递归:一个函数直接或间接地调用自身,必须有一个明确的递归终止条件,否则会导致栈溢出。
示例代码(求阶乘)
#include <stdio.h>
// 函数声明
long factorial(int n);
int main() {
int num = 5;
printf("The factorial of %d is %ld\n", num, factorial(num));
return 0;
}
// 函数定义:使用递归
long factorial(int n) {
if (n == 0 || n == 1) { // 递归终止条件
return 1;
} else {
return n * factorial(n - 1); // 递归调用
}
}
数组与字符串
处理批量数据的基本数据结构。
核心概念
- 数组:一组相同类型的数据元素的集合,通过索引访问。
- 字符串:在C语言中,字符串是以
'\0'(空字符) 结尾的字符数组。
关键知识点
- 一维数组:
数据类型 数组名[数组大小];,如int scores[10];。 - 字符串处理函数(需包含
<string.h>):strcpy(dest, src):复制字符串。strlen(str):计算字符串长度(不包括'\0')。strcmp(str1, str2):比较两个字符串。strcat(dest, src):连接字符串。
- 重要区别:
char str1[] = "hello";和char *str2 = "hello";,前者是字符数组,内容可修改;后者是指向字符串字面量的指针,内容通常不可修改。
示例代码(冒泡排序)
#include <stdio.h>
void bubbleSort(int arr[], int n);
int main() {
int i;
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
printf("Sorted array: \n");
for (i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
// 冒泡排序函数
void bubbleSort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
// 交换
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
指针
C语言的灵魂,也是其最强大的特性,但也是最容易出错的地方。
核心概念
- 指针:一个变量,其值为另一个变量的内存地址。
- 内存地址:内存中每个字节的唯一编号。
- 指针运算:通过指针间接访问和修改内存。
关键知识点
- 指针声明:
数据类型 *指针变量名;,如int *p;。 - 取地址运算符
&:获取变量的内存地址。 - *解引用/间接寻址运算符 ``**:获取指针指向地址处的值。
- 指针与数组:数组名在大多数情况下会“退化”为其首元素的地址。
p = arr;和p = &arr[0];是等价的,可以通过指针遍历数组。 - 指针与函数:通过传递指针给函数,可以在函数内部修改外部变量的值(模拟引用传递),或者避免传递大型数据结构带来的开销。
示例代码(通过指针交换两个数)
#include <stdio.h>
// 使用指针作为参数,可以修改主函数中的值
void swap(int *ptr1, int *ptr2) {
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
int main() {
int a = 10, b = 20;
int *pa = &a; // pa指向a
int *pb = &b; // pb指向b
printf("Before swap: a = %d, b = %d\n", a, b);
swap(pa, pb); // 传递指针
printf("After swap: a = %d, b = %d\n", a, b);
return 0;
}
结构体、联合体与枚举
将不同类型的数据组合成一个自定义的类型。
核心概念
- 结构体:将不同类型的数据成员打包成一个整体。
- 联合体:所有成员共享同一段内存,任何时刻只有一个成员有效。
- 枚举:定义一组命名的整数常量。
关键知识点
-
结构体定义与使用:
(图片来源网络,侵删)struct Student { char name[50]; int age; float score; }; struct Student s1; strcpy(s1.name, "Zhang San"); s1.age = 20; -
指向结构体的指针:使用
->运算符通过指针访问成员,如ptr->name。
文件操作
实现数据的持久化存储。
核心概念
- 文件指针:指向
FILE结构体的指针,用于标识和操作文件。 - 文件打开与关闭:
fopen()和fclose()。 - 文件读写:
fgetc(),fputc(),fgets(),fputs(),fscanf(),fprintf()。
关键知识点
- 打开模式:
"r":只读"w":只写(覆盖)"a":追加"r+":读写
- 错误检查:每次文件操作后,都应检查操作是否成功(如
fopen是否返回NULL)。
学习建议与最佳实践
- 动手编码,不要只看:C语言是实践性极强的学科,每个知识点都要亲自敲代码、调试、运行。
- 善用调试器:学习使用
gdb(Linux) 或 Visual Studio 的调试器,单步执行、观察变量值的变化是理解程序运行流程的利器。 - 理解内存模型:花时间理解栈、堆、全局/静态区、代码区,理解了内存,就理解了指针、函数调用和大部分复杂问题的根源。
- 编写可读性高的代码:
- 使用有意义的变量名和函数名。
- 适当使用缩进和空格。
- 添加必要的注释。
- 阅读优秀代码:阅读一些开源项目(如
SQLite的一部分)的源码,学习大师的编程风格和技巧。 - 从C到C++:在掌握了C语言后,可以学习C++,C++在C的基础上增加了面向对象、泛型编程等特性,能让你从更抽象的层次思考问题。
祝您学习顺利,在C语言的世界里探索愉快!
