C语言程序设计教程与上机指导
前言
C语言是计算机科学的基石,它不仅是一门功能强大、效率极高的编程语言,更是理解计算机底层工作原理和掌握其他现代编程语言(如C++, Java, C#)的钥匙,本教程旨在通过“理论讲解 + 上机实践”相结合的方式,带领读者从零开始,循序渐进地掌握C语言的精髓。

第一部分:C语言教程
第1章:C语言概述
1 什么是C语言? C语言由丹尼斯·里奇于1972年在贝尔实验室发明,最初用于编写Unix操作系统,它是一种过程化、结构化、中级语言,兼具高级语言的易用性和低级语言的高效性。
2 为什么学习C语言?
- 效率高:生成的代码执行速度快,内存占用小。
- 可移植性强:C语言程序可以在不同平台(Windows, Linux, macOS)上轻松编译和运行。
- 基础性强:是学习操作系统、数据结构、嵌入式开发等课程的必修语言。
- 接近硬件:能让你更深入地理解计算机内存、指针等核心概念。
3 C语言程序的基本结构 一个最简单的C语言程序通常包含以下几个部分:
#include <stdio.h> // 1. 预处理指令:包含标准输入输出库
int main() { // 2. 主函数:程序的入口点
// 3. 变量声明
int a = 10;
char b = 'A';
// 4. 功能执行语句
printf("Hello, World!\n"); // 调用库函数,在屏幕上打印文本
printf("a = %d, b = %c\n", a, b);
// 5. 返回语句:main函数的返回值,0表示程序正常结束
return 0;
}
第2章:数据类型、运算符与表达式
1 关键字与标识符

- 关键字:C语言预先定义好的、有特殊含义的单词(如
int,if,for,return),不能用作自定义名称。 - 标识符:程序员自己定义的名称,用于变量、函数等,规则:由字母、数字、下划线组成,且不能以数字开头。
2 基本数据类型
| 类型 | 关键字 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| 整型 | int | 存储整数 | int age = 25; |
| 字符型 | char | 存储单个字符 | char grade = 'A'; |
| 浮点型(单精度)| float | 存储带小数的数字,约6-7位有效数字 | float price = 19.99; |
| 浮点型(双精度)| double | 存储带小数的数字,约15-16位有效数字 | double pi = 3.1415926535; |
3 变量与常量
- 变量:在程序运行过程中其值可以改变的量,使用前必须先声明。
int score; // 声明 score = 95; // 赋值
- 常量:在程序运行过程中其值不能改变的量。
#define宏定义:#define PI 3.14const关键字:const int MAX_NUM = 100;
4 运算符
- 算术运算符:, , , , (取模)
- 关系运算符:
>,<,>=,<=, (等于), (不等于) -> 返回结果为1(真) 或0(假)。 - 逻辑运算符:
&&(与), (或), (非) - 赋值运算符:, , , ,
- 自增/自减运算符:, (前置和后置效果不同)
- sizeof 运算符:计算变量或类型所占的字节数。
sizeof(int)。
第3章:流程控制
1 顺序结构 程序按代码书写的顺序,从上到下依次执行。

2 选择结构
- if-else 语句:根据条件执行不同的代码块。
if (score >= 60) { printf("及格\n"); } else { printf("不及格\n"); } - switch 语句:用于多分支选择。
switch (grade) { case 'A': printf("优秀"); break; case 'B': printf("良好"); break; default: printf("其他"); }
3 循环结构
- for 循环:当循环次数已知时最常用。
for (int i = 0; i < 10; i++) { printf("%d ", i); } - while 循环:当循环条件满足时,重复执行。
int i = 0; while (i < 10) { printf("%d ", i); i++; } - do-while 循环:先执行一次循环体,再判断条件。
int i = 0; do { printf("%d ", i); i++; } while (i < 10); break和continue:break:立即跳出当前循环或switch语句。continue:跳过本次循环的剩余语句,直接进入下一次循环。
第4章:函数
1 函数的定义与调用 函数是组织好的、可重复使用的、用于执行特定任务的代码块。
- 定义:
返回类型 函数名(参数列表) { 函数体; } - 调用:
函数名(实际参数);
2 函数参数传递 C语言中,函数参数传递是值传递(Pass by Value),这意味着函数内部接收的是实参的副本,修改副本不会影响实参的值。
3 函数的声明与定义
- 声明:告诉编译器函数的存在和它的接口(返回类型、函数名、参数列表)。
int add(int, int); - 定义:提供函数的具体实现。
- 库函数:C标准库提供了大量预定义的函数,如
printf,scanf,sqrt等,使用时需包含对应的头文件(如stdio.h,math.h)。
第5章:数组
1 一维数组
- 定义:
数据类型 数组名[数组长度];int scores[5]; // 定义一个可以存放5个整数的数组 - 初始化:
int nums[5] = {1, 2, 3, 4, 5}; - 访问:通过下标(从0开始)访问元素。
printf("%d", nums[0]);
2 二维数组
- 定义:
数据类型 数组名[行数][列数];int matrix[3][4]; // 定义一个3行4列的二维数组 - 初始化:
int m[2][2] = {{1,2}, {3,4}};
第6章:指针
1 指针是什么? 指针是一个变量,其存储的值是另一个变量的内存地址,它提供了直接操作内存的能力。
2 指针的定义与使用
- 定义:
数据类型 *指针变量名;int *p; // 定义一个指向整型数据的指针 - 取地址运算符
&:获取变量的内存地址。int a = 10;p = &a; // 将变量a的地址赋给指针p - *解引用运算符 `
**:通过指针访问其指向内存中的值。printf("%d", *p); // 输出10`
3 指针与数组 数组名在大多数情况下会“退化”为其首元素的地址,可以使用指针来遍历数组。
int arr[3] = {10, 20, 30};
int *p = arr; // p指向arr[0]
printf("%d ", *p++); // 输出10,然后p指向arr[1]
4 指针与函数 通过传递指针给函数,可以实现地址传递,从而在被调用函数中修改主调函数变量的值。
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
int main() {
int a = 5, b = 10;
swap(&a, &b); // 传递a和b的地址
printf("a = %d, b = %d\n", a, b); // 输出 a = 10, b = 5
return 0;
}
第7章:结构体、联合体与枚举
1 结构体 将不同类型的数据组合成一个整体。
struct Student {
int id;
char name[50];
float score;
};
int main() {
struct Student s1;
s1.id = 101;
strcpy(s1.name, "Zhang San");
s1.score = 88.5;
return 0;
}
2 联合体 所有成员共享同一段内存空间,同一时间只能存储一个成员的值。
3 枚举 将变量的值限定在一个有限的集合内。
enum Weekday {MON, TUE, WED, THU, FRI, SAT, SUN};
enum Weekday today = MON;
第8章:文件操作
1 文件指针
进行文件操作前,需要定义一个指向 FILE 结构体的指针。
FILE *fp;
2 常用文件操作函数
fopen(filename, mode):打开文件。- 模式:
"r"(只读),"w"(只写, 会覆盖),"a"(追加),"r+"(读写)。
- 模式:
fclose(fp):关闭文件。fgetc(fp)/fputc(c, fp):字符读写。fgets(s, n, fp)/fputs(s, fp):字符串读写。fprintf(fp, format, ...)/fscanf(fp, format, ...):格式化读写。fread(buffer, size, count, fp)/fwrite(buffer, size, count, fp):二进制块读写。
第9章:预处理器
预处理器在编译之前对源代码进行处理。
#include:包含文件。#define:定义宏(常量或带参数的函数)。#ifdef,#ifndef,#endif:条件编译。
第二部分:上机指导
上机实践是掌握C语言的关键,请务必跟随教程,完成以下练习。
实验1:熟悉C语言开发环境
- 目的:学会安装和使用C语言编译器(如GCC, MinGW, Visual Studio, Dev-C++等),并成功编译、运行第一个C程序。
- 任务:
- 安装你选择的开发环境。
- 输入本章开头的 "Hello, World!" 程序。
- 编译、链接并运行该程序。
- 尝试修改程序,让它打印你的名字。
实验2:数据类型与运算符
- 目的:掌握基本数据类型的使用和各类运算符的优先级。
- 任务:
- 编写一个程序,声明一个整型、一个浮点型、一个字符型变量,并分别赋值。
- 使用
printf将它们的值打印出来。 - 计算并打印一个圆的周长和面积(使用
#define定义PI)。 - 验证 运算符前置和后置的区别。
实验3:流程控制
- 目的:熟练使用
if-else和switch语句,以及for,while,do-while循环。 - 任务:
- 判断题:编写程序,输入一个整数,判断它是奇数还是偶数。
- 分支题:输入一个学生的百分制成绩,输出其对应的等级(90-100:A, 80-89:B, ...)。
- 循环题1:使用
for循环打印1到100之间所有能被3整除的数。 - 循环题2:使用
while循环计算1到100的和。 - 循环题3:使用
do-while循环实现一个简单的猜数字游戏(预设一个数字,让用户输入猜测,直到猜对为止)。
实验4:函数
- 目的:理解函数的定义、声明、调用和参数传递机制。
- 任务:
- 编写一个函数
int max(int a, int b),返回两个数中的较大者,在main函数中调用它。 - 编写一个函数
void isPrime(int num),判断一个数是否为素数,并在函数内部打印结果。 - 挑战:使用指针参数编写一个函数
void swap(int *a, int *b),交换两个变量的值,并在main函数中验证交换是否成功。
- 编写一个函数
实验5:数组
- 目的:掌握一维和二维数组的定义、初始化、遍历和常用操作。
- 任务:
- 一维数组:定义一个包含10个整数的数组,用循环为其赋值为1到10,然后逆序打印所有元素。
- 一维数组:从键盘输入5个学生的成绩,存入数组,计算并打印平均分。
- 二维数组:定义一个3x3的二维数组,并初始化为单位矩阵(对角线为1,其余为0),然后打印它。
实验6:指针
- 目的:深入理解指针的概念,并熟练使用指针操作数组和函数。
- 任务:
- 指针基础:定义一个整型变量和一个指向它的指针,通过指针修改变量的值并打印。
- 指针与数组:使用指针遍历实验5中的一维数组,并打印所有元素。
- 指针与字符串:使用指针实现一个函数
int myStrlen(char *str),用于计算字符串的长度(不能使用strlen库函数)。 - 指针与函数:重写实验4中的“交换两个变量”的函数,确保你完全理解地址传递的原理。
实验7:综合项目(简易学生成绩管理系统)
- 目的:综合运用前面所学的知识(结构体、数组、指针、文件、函数),解决一个实际问题。
- 任务:
- 定义结构体:使用
struct定义一个学生信息结构体,包含学号、姓名、多门课程成绩。 - 功能模块化:将程序功能分解为多个函数,如:
void addStudent(struct Student students[], int *count):添加学生信息。void displayStudents(struct Student students[], int count):显示所有学生信息。void saveToFile(struct Student students[], int count):将学生信息保存到文件。void loadFromFile(struct Student students[], int *count):从文件加载学生信息。
- 主菜单:在
main函数中编写一个循环,显示一个菜单供用户选择(1.添加 2.显示 3.保存 4.读取 5.退出)。 - 文件持久化:实现保存和加载功能,使程序关闭后数据不丢失。
- 定义结构体:使用
总结与建议
- 多动手,少眼高手低:编程是一门实践性极强的技能,光看不练是学不会的。
- 调试是程序员的必备技能:遇到错误不要慌,学会使用编译器提示和调试工具(如GDB)来定位和解决问题。
- 多读代码,多写代码:阅读优秀的开源代码,模仿和重构,能极大地提升你的编程水平。
- 理解原理,而非死记硬背:理解指针、内存、栈、堆等底层概念,会让你对C语言有更深刻的认识。
祝你学习顺利,早日成为C语言高手!
