以下答案和解析是为学习和参考目的而提供的,直接复制粘贴代码而不理解其原理,对编程学习毫无益处,强烈建议您先独立思考,尝试自己编写代码,遇到困难时再参考以下内容,以查漏补缺,编程能力的提升来自于大量的练习和思考。

本书由谭浩强老师编写,是国内非常经典的C语言入门教材,由于不同出版社、不同印刷版本的课后习题顺序和内容可能存在细微差异,以下答案将按照最广泛流传的版本进行组织。
第1章 C语言概述
本章主要考察对C语言基本概念的理解,通常以简答题为主。
1 什么是结构化程序设计?它的主要特点是什么?
- 答: 结构化程序设计是一种编程思想和方法,旨在使程序结构清晰、可读性强、易于调试和维护。
- 主要特点:
- 自顶向下: 将一个复杂的大问题分解成若干个相对独立的小问题,再逐步细化小问题。
- 逐步求精: 对每个小问题,再进一步分解成更简单的功能模块,直到可以用基本的、简单的语句实现。
- 模块化设计: 程序由若干个功能模块(函数)组成,每个模块负责一个特定的功能,模块之间接口清晰。
- 使用三种基本结构: 任何复杂的程序都可以由顺序结构、选择结构(分支结构)和循环结构这三种基本结构组合而成。
2 写出一个C程序的基本结构。

-
答: 一个完整的C程序通常包括:
- 包含头文件: 使用
#include指令引入标准库或其他头文件。 - 主函数:
main()函数是程序的入口点,程序从这里开始执行。 - 变量声明: 在函数内部声明需要用到的变量。
- 执行语句: 由各种表达式、函数调用等组成的语句序列,完成具体功能。
- 返回值:
main()函数结尾通常使用return语句返回一个状态码(0表示成功)。
- 包含头文件: 使用
-
示例:
#include <stdio.h> // 包含标准输入输出库 int main() // 主函数 { // 变量声明 int a = 10; int b = 20; int sum; // 执行语句 sum = a + b; printf("The sum is: %d\n", sum); // 调用printf函数输出结果 return 0; // 返回0,表示程序正常结束 }
第2章 数据类型、运算符与表达式
本章是C语言的基础,重点考察变量、数据类型、运算符的使用。
1 请将以下数学表达式写成C语言表达式。

- 原式:
(a+b)/(c-d) - C语言表达式:
(a + b) / (c - d)- 注意: 当
c-d的结果为0时,程序会因除零错误而崩溃,在实际编程中需要增加判断。
- 注意: 当
2 分析以下程序的输出结果。
#include <stdio.h>
int main()
{
int x = 10, y = 20;
int z = x++ + y++; // x=10, y=20
printf("x=%d, y=%d, z=%d\n", x, y, z); // x=11, y=21, z=30
return 0;
}
- 输出结果:
x=11, y=21, z=30 - 解析:
x++和y++都是后置自增,在表达式中,它们会先使用当前值(x=10, y=20)进行计算,计算完成后再自增。z = 10 + 20,z的值是30。- 表达式计算完毕后,
x自增为11,y自增为21。
3 写一个程序,从键盘输入一个大写字母,将其转换为小写字母后输出。
-
思路: 利用ASCII码的规律,大写字母的ASCII码值比对应的小写字母小32。'A'的ASCII码是65,'a'的ASCII码是97。
-
代码:
#include <stdio.h> int main() { char upper_char, lower_char; printf("Please input an uppercase letter: "); scanf("%c", &upper_char); // 输入一个大写字母 lower_char = upper_char + 32; // 转换为小写 printf("The lowercase letter is: %c\n", lower_char); return 0; }
第3章 顺序与选择结构
本章重点考察 if-else、switch 语句的使用。
1 编写程序,判断一个整数是奇数还是偶数。
-
思路: 判断一个数能否被2整除,如果能,是偶数;否则,是奇数,可以使用取模运算符 。
-
代码:
#include <stdio.h> int main() { int num; printf("Please input an integer: "); scanf("%d", &num); if (num % 2 == 0) { printf("%d is an even number.\n", num); } else { printf("%d is an odd number.\n", num); } return 0; }
2 使用 switch 语句,根据输入的数字(1-7)输出对应的星期几。
-
思路:
switch语句非常适合处理多分支情况,注意case后的值必须是常量,且switch表达式的类型要与case后的类型匹配,最后加一个default分支处理非法输入。 -
代码:
#include <stdio.h> int main() { int day; printf("Please input a number (1-7): "); scanf("%d", &day); switch (day) { case 1: printf("Monday\n"); break; case 2: printf("Tuesday\n"); break; case 3: printf("Wednesday\n"); break; case 4: printf("Thursday\n"); break; case 5: printf("Friday\n"); break; case 6: printf("Saturday\n"); break; case 7: printf("Sunday\n"); break; default: printf("Invalid input! Please enter a number between 1 and 7.\n"); break; } return 0; }- 注意: 每个
case后的break;语句非常重要,用于跳出switch结构,如果没有break,程序会继续执行下一个case。
- 注意: 每个
第4章 循环结构
本章重点考察 for、while、do-while 循环以及 break、continue 的使用。
1 求 1 到 100 之间所有偶数的和。
-
思路1: 使用
for循环,从1到100遍历,用if判断是否为偶数,如果是则累加。 -
思路2(更高效): 观察可知,1到100的偶数是一个等差数列(2, 4, 6, ..., 100),可以直接让循环变量从2开始,步长为2。
-
代码(思路2):
#include <stdio.h> int main() { int sum = 0; for (int i = 2; i <= 100; i += 2) { sum += i; } printf("The sum of even numbers from 1 to 100 is: %d\n", sum); return 0; }
2 打印出所有的“水仙花数”,水仙花数是指一个三位数,其各位数字立方和等于它本身,153 = 1³ + 5³ + 3³。
-
思路: 使用
for循环遍历所有的三位数(100-999),对于每个数,分离出其百位、十位和个位,然后计算它们的立方和,并与原数比较。 -
代码:
#include <stdio.h> int main() { int i, a, b, c; printf("Narcissistic numbers between 100 and 999 are:\n"); for (i = 100; i < 1000; i++) { a = i / 100; // 百位 b = (i / 10) % 10; // 十位 c = i % 10; // 个位 if (i == a*a*a + b*b*b + c*c*c) { printf("%d\n", i); } } return 0; }
第5章 函数
本章重点考察函数的定义、声明、调用、参数传递(值传递)、函数的嵌套与递归。
1 编写一个函数 is_prime(int n),判断一个整数 n 是否为素数(质数),在 main 函数中调用该函数,并输出100以内的所有素数。
-
思路: 素数是指只能被1和它本身整除的大于1的自然数,判断一个数
n是否为素数,只需用2到sqrt(n)之间的整数去试除即可,如果有一个能整除,则不是素数。 -
代码:
#include <stdio.h> #include <math.h> // 需要包含此头文件以使用sqrt函数 // 函数声明 int is_prime(int n); int main() { printf("Prime numbers between 1 and 100 are:\n"); for (int i = 2; i <= 100; i++) { if (is_prime(i)) { printf("%d ", i); } } printf("\n"); return 0; } // 函数定义 int is_prime(int n) { if (n <= 1) { return 0; // 1和负数、0都不是素数 } for (int i = 2; i <= sqrt(n); i++) { if (n % i == 0) { return 0; // 如果能被整除,则不是素数 } } return 1; // 否则是素数 }
2 使用递归方法计算斐波那契数列的第n项,斐波那契数列定义:F(1)=1, F(2)=1, F(n)=F(n-1)+F(n-2) (n>2)。
-
思路: 递归的精髓在于找到“递归出口”(基本情况)和“递归规则”(调用自身)。
- 递归出口: 当
n == 1或n == 2时,返回1。 - 递归规则: 当
n > 2时,返回fibonacci(n-1) + fibonacci(n-2)。
- 递归出口: 当
-
代码:
#include <stdio.h> // 函数声明 int fibonacci(int n); int main() { int n; printf("Please input the term number n: "); scanf("%d", &n); if (n <= 0) { printf("Invalid input! n must be a positive integer.\n"); } else { printf("The %dth term of Fibonacci sequence is: %d\n", n, fibonacci(n)); } return 0; } // 函数定义 int fibonacci(int n) { if (n == 1 || n == 2) { return 1; } else { return fibonacci(n - 1) + fibonacci(n - 2); } }- 注意: 递归方法虽然简洁,但对于较大的
n值效率很低,因为存在大量的重复计算,在实际应用中,通常使用循环或动态规划来优化。
- 注意: 递归方法虽然简洁,但对于较大的
第6章 数组
本章重点考察一维数组、二维数组的定义、初始化、引用以及与循环结合的使用。
1 有一个已排好序的数组,要求输入一个数,按原来排序的规律将它插入到数组中。
-
思路:
- 找到该数在数组中应插入的位置
i(即第一个大于等于该数的位置)。 - 将从位置
i开始到数组末尾的所有元素都向后移动一位。 - 将新数放入位置
i。
- 找到该数在数组中应插入的位置
-
代码(假设为升序排列):
#include <stdio.h> #define N 10 // 定义数组初始大小 int main() { int a[N + 1] = {1, 4, 6, 9, 13, 16, 28, 40, 100}; // 初始数组,留一个空位 int len = 9; // 当前数组长度 int num, i, j; printf("The original array is:\n"); for (i = 0; i < len; i++) { printf("%d ", a[i]); } printf("\n"); printf("Please input a number to insert: "); scanf("%d", &num); // 1. 找到插入位置 for (i = 0; i < len; i++) { if (a[i] > num) { break; } } // 循环结束后,i就是插入位置 // 2. 将后面的元素后移 for (j = len; j > i; j--) { a[j] = a[j - 1]; } // 3. 插入新元素 a[i] = num; len++; // 数组长度增加1 printf("The array after insertion is:\n"); for (i = 0; i < len; i++) { printf("%d ", a[i]); } printf("\n"); return 0; }
2 将一个3x3的矩阵转置。
-
思路: 矩阵转置即将行和列互换,对于方阵,只需遍历矩阵的上三角(或下三角)部分,将
a[i][j]和a[j][i]交换即可。 -
代码:
#include <stdio.h> #define N 3 int main() { int a[N][N] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int i, j, temp; printf("Original matrix:\n"); for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%d ", a[i][j]); } printf("\n"); } // 转置操作 for (i = 0; i < N; i++) { for (j = i + 1; j < N; j++) // 注意:j从i+1开始,避免交换两次又变回去 { temp = a[i][j]; a[i][j] = a[j][i]; a[j][i] = temp; } } printf("\nTransposed matrix:\n"); for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%d ", a[i][j]); } printf("\n"); } return 0; }
第7章 指针
本章是C语言的难点和重点,考察指针的定义、指针与数组、指针与函数、指针数组等。
1 使用指针变量将数组 a 中的n个整数按相反顺序存放。
-
思路: 定义一个指向数组首元素的指针
p_start和一个指向数组最后一个元素的指针p_end,交换它们所指向的元素,p_start向后移动,p_end向前移动,直到两个指针相遇或交错。 -
代码:
#include <stdio.h> void reverse_array(int *arr, int n); int main() { int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int n = sizeof(a) / sizeof(a[0]); printf("Original array:\n"); for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); reverse_array(a, n); printf("Reversed array:\n"); for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); return 0; } void reverse_array(int *arr, int n) { int *p_start = arr; int *p_end = arr + n - 1; int temp; while (p_start < p_end) { // 交换元素 temp = *p_start; *p_start = *p_end; *p_end = temp; // 移动指针 p_start++; p_end--; } }
2 编写一个函数 str_copy(char *dest, const char *src),将字符串 src 复制到字符串 dest 中。
-
思路: 使用两个指针分别指向源字符串和目标字符串的起始位置,遍历源字符串,将每个字符复制到目标字符串中,直到遇到字符串结束符
\0,在目标字符串末尾手动添加\0。 -
代码:
#include <stdio.h> void str_copy(char *dest, const char *src); int main() { char src[] = "Hello, World!"; char dest[50]; // 确保目标数组足够大 str_copy(dest, src); printf("Source string: %s\n", src); printf("Copied string: %s\n", dest); return 0; } void str_copy(char *dest, const char *src) { while (*src != '\0') { *dest = *src; dest++; src++; } *dest = '\0'; // 别忘了添加字符串结束符 }
第8章 结构体与共用体
本章重点考察结构体类型的定义、结构体变量的初始化和成员访问。
1 定义一个结构体变量(包括年、月、日),计算该日期是本年度的第几天。
-
思路:
- 定义一个包含
year,month,day成员的结构体Date。 - 创建一个数组来存储每个月的天数(注意2月要考虑闰年)。
- 遍历输入的月份,将前
month-1个月的天数累加起来,最后加上输入的day。 - 判断闰年:能被4整除但不能被100整除,或者能被400整除的年份是闰年。
- 定义一个包含
-
代码:
#include <stdio.h> // 定义结构体 struct Date { int year; int month; int day; }; // 判断是否为闰年 int is_leap_year(int year) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { return 1; } return 0; } int main() { struct Date date; int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int day_of_year = 0; printf("Please input date (year month day, e.g., 2025 10 26): "); scanf("%d %d %d", &date.year, &date.month, &date.day); // 如果是闰年,2月有29天 if (is_leap_year(date.year)) { days_in_month[1] = 29; } // 累加前 month-1 个月的天数 for (int i = 0; i < date.month - 1; i++) { day_of_year += days_in_month[i]; } // 加上当月的天数 day_of_year += date.day; printf("It is the %dth day of %d.\n", day_of_year, date.year); return 0; }
第9章 文件
本章重点考察文件的打开、关闭、读写操作。
1 从键盘输入一行字符,将其写入到一个名为 test.txt 的文本文件中,然后再从该文件中读出并显示在屏幕上。
-
思路:
- 使用
fopen("test.txt", "w")以写入模式打开文件。 - 使用
getchar()或fgets()从键盘读取一行字符。 - 使用
fputs()或fprintf()将字符写入文件。 - 使用
fclose()关闭文件。 - 再次使用
fopen("test.txt", "r")以读取模式打开文件。 - 使用
fgets()或fscanf()从文件中读取内容。 - 使用
printf()将内容显示在屏幕上。 - 再次关闭文件。
- 使用
-
代码:
#include <stdio.h> #include <string.h> int main() { FILE *fp; char str[256]; // --- 写入文件 --- fp = fopen("test.txt", "w"); // 以写入模式打开文件 if (fp == NULL) { printf("Cannot open file for writing.\n"); return 1; } printf("Please input a string to write to file: "); // 使用 fgets 读取一行,包括空格 fgets(str, sizeof(str), stdin); fputs(str, fp); // 将字符串写入文件 fclose(fp); // 关闭文件 // --- 读取文件 --- fp = fopen("test.txt", "r"); // 以读取模式打开文件 if (fp == NULL) { printf("Cannot open file for reading.\n"); return 1; } printf("\nContent read from file:\n"); // 使用 fgets 读取一行 while (fgets(str, sizeof(str), fp) != NULL) { printf("%s", str); } fclose(fp); // 关闭文件 return 0; }
希望这些答案和解析对您有帮助!祝您学习顺利!
