摘要
本文聚焦C语言学习,以系列练习题深入剖析其重要知识点。开篇点明练习对巩固知识的重要性,随后详细解读各题。涵盖数据定义输出、圆周长计算、条件分支判断、循环应用、水仙花数判断、函数与数组操作,还涉及文件读写、宏定义及指针运用等。通过登录验证、递归、查找排序等经典案例,全面覆盖C语言基础语法、控制结构、函数数组、文件操作、预处理指令及指针等内容,助力学习者提升编程实践能力。
目录
C 语言学习之路:练习题实战记录
在 C 语言的学习过程中,练习是巩固知识、提升编程能力的关键。下面是我在学习 C 语言时完成的一些练习题,涵盖了数据定义、基本运算、流程控制、函数使用等多个重要知识点,每一道题都承载着我对 C 语言理解的深入和编程技巧的提升。
练习题 1:数据定义与输出
题目描述
使用全局#define
定义gender
为’男’。使用局部定义name
(长度为 12)为张三,age
为 22,height
为 1.78,并按格式name gender age height
输出完整结果。
代码实现
#include <stdio.h>
#define gender "男"
int main() {
char name[12] = "张三";
int age = 22;
float height = 1.78;
printf("%s %s %d %.2f\n", name, gender, age, height);
return 0;
}
代码分析
#define
宏定义:通过#define gender "男"
,定义了一个全局的宏gender
,在后续代码中,所有出现gender
的地方都会被替换为"男"
。- 局部变量定义:在
main
函数中,定义了字符数组name
来存储姓名,整型变量age
存储年龄,浮点型变量height
存储身高。 - 输出函数:使用
printf
函数按照指定格式输出各个变量的值,%.2f
表示将浮点数height
保留两位小数输出。
练习题 2:计算圆的周长
题目描述
要求用户输入圆的半径,根据公式计算圆的周长并输出。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define PI 3.14159
int main() {
float radius;
printf("请输入圆的半径: ");
scanf("%f", &radius);
float circumference = 2 * PI * radius;
printf("圆的周长是: %.2f\n", circumference);
return 0;
}
代码分析
- 宏定义常量:
#define PI 3.14159
定义了圆周率PI
,方便在代码中使用,避免了硬编码带来的维护问题。 - 用户输入:使用
printf
提示用户输入半径,然后通过scanf("%f", &radius)
读取用户输入的浮点数并存储到radius
变量中。 - 计算与输出:根据圆的周长公式
2 * PI * radius
计算周长,并使用printf
函数输出结果,同样保留两位小数。
练习题 3:条件判断与分支结构
题目描述
- 使用
if - else
结构判断用户是否中奖,中奖号码随机生成。 - 使用
switch - case
结构根据用户输入对电脑进行操作(0 - 关机;1 - 重启;2 - 睡眠)。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {
srand(time(0));
int luckyNumber = rand() % 10;
int userInput;
printf("请输入一个数字:");
scanf("%d", &userInput);
if (userInput == luckyNumber) {
printf("你中奖了!\n");
}
else {
printf("你未中奖!\n");
}
// switch - 用户对电脑指令操作
int operation;
printf("请输入操作指令 (0 - 关机; 1 - 重启; 2 - 睡眠):");
scanf("%d", &operation);
switch (operation)
{
case 0:
printf("正在关机...\n");
break;
case 1:
printf("正在重启...\n");
break;
case 2:
printf("正在睡眠...\n");
break;
default:
printf("无效操作!\n");
break;
}
return 0;
}
代码分析
- 随机数生成与中奖判断:
srand(time(0))
用于初始化随机数种子,使每次程序运行时生成的随机数不同。rand() % 10
生成一个 0 到 9 之间的随机数作为中奖号码。- 通过
if - else
结构判断用户输入的数字与中奖号码是否一致,给出相应提示。
switch - case
结构:根据用户输入的操作指令,使用switch - case
结构执行不同的操作,default
分支处理无效输入。
练习题 4:循环与条件判断
题目描述
使用for
循环打印【1 - 100】内的能被 3 和 7 整除的数,并输出满足条件的个数。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int count = 0;
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 7 == 0) {
printf("%d\n", i);
count++;
}
}
printf("count=%d\n", count);
return 0;
}
代码分析
- 循环遍历:
for
循环从 1 到 100 遍历每个整数。 - 条件判断:使用
if
语句判断当前整数是否能同时被 3 和 7 整除,即i % 3 == 0 && i % 7 == 0
。 - 计数与输出:满足条件的数被打印出来,同时计数器
count
加 1,最后输出满足条件的数的个数。
练习题 5:嵌套循环应用 - 打印 99 乘法表
题目描述
打印 99 乘法表。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
for (int i = 1; i < 10; i++) {
for (int j = 1; j <= i; j++) {
printf("%d*%d=%d\t", i, j, i * j);
}
printf("\n");
}
return 0;
}
代码分析
- 嵌套循环:外层
for
循环控制行数i
,从 1 到 9;内层for
循环控制列数j
,从 1 到当前行号i
。 - 输出格式:使用
printf
函数输出乘法表达式,\t
用于控制输出格式,使表格对齐美观,内层循环结束后换行。
练习题 6:判断水仙花数
题目描述
判断【100,999】内的水仙花数(水仙花数是一个 3 位数,且每个位的立方和等于这个数本身),并打印出来。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
for (int i = 100; i <= 999; i++)
{
int a = i / 100;
int b = i / 10 % 10;
int c = i % 10;
if (i == a * a * a + b * b * b + c * c * c)
{
printf("%d\n", i);
}
}
return 0;
}
代码分析
- 数字拆分:通过整除和取余运算,将三位数
i
拆分为百位a
、十位b
和个位c
。 - 条件判断:使用
if
语句判断当前数是否为水仙花数,即i == a * a * a + b * b * b + c * c * c
。 - 输出结果:满足条件的水仙花数被打印出来。
练习题 7:函数与数组操作
题目描述
利用调用函数的方法找出数组a = {12, 23, 56, 45, 64}
的最大值,并将数组降序排列输出为新的数组b
。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 找出数组的最大值
int findMax(int a[], int size) {
int max = a[0];
for (int i = 1; i < size; i++) {
if (a[i] > max) {
max = a[i];
}
}
return max;
}
// 降序排序
void descendingSort(int a[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (a[j] < a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
int main() {
int a[] = { 12, 23, 56, 45, 64 };
int size = sizeof(a) / sizeof(a[0]);
int max = findMax(a, size);
printf("max = %d\n", max);
// 降序排列
descendingSort(a, size);
printf("降序排列数组:");
for (int i = 0; i < size; i++)
{
printf("%d ", a[i]);
}
return 0;
}
代码分析
- 函数定义:
findMax
函数用于找出数组中的最大值,通过遍历数组比较每个元素得到最大值。descendingSort
函数使用冒泡排序算法对数组进行降序排列。
- 主函数操作:在
main
函数中,定义数组a
,计算数组大小,调用findMax
函数找到最大值并输出,调用descendingSort
函数对数组进行降序排列后输出。
通过完成这些练习题,我对 C 语言的基本语法、控制结构、函数和数组的使用有了更深入的理解和掌握。每一道题都是一次成长的机会,让我在 C 语言的学习道路上不断前进,也期待在未来的学习中能够挑战更多复杂的编程任务,进一步提升自己的编程能力。
在 C 语言的学习过程中,文件读写操作、预处理指令以及指针的灵活运用是非常重要的知识点。下面将通过几个具体的练习题来深入探讨这些内容。
练习题 8:文件读写操作
题目描述
本题要求完成文件的写入和读取操作。首先将字符串 “Hello World!” 写入到 test.txt
文件中,然后再从该文件中读取内容并输出。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
// 写入文件
FILE* fp = fopen("test.txt", "w");
if (fp != NULL) {
fputs("Hello, World!", fp);
fclose(fp);
printf("成功将内容写入文件。\n");
} else {
printf("无法打开文件进行写入操作。\n");
return 1;
}
// 读取文件
fp = fopen("test.txt", "r");
if (fp != NULL) {
char buffer[100];
fgets(buffer, sizeof(buffer), fp);
printf("文件内容: %s\n", buffer);
fclose(fp);
} else {
printf("无法打开文件进行读取操作。\n");
return 1;
}
return 0;
}
代码解释
- 文件写入部分:
- 使用
fopen("test.txt", "w")
以写入模式打开文件。若文件打开成功,fopen
函数会返回一个指向FILE
结构体的指针;若失败则返回NULL
。 fputs("Hello, World!", fp)
将字符串 “Hello, World!” 写入文件。fclose(fp)
关闭文件,释放相关资源。
- 使用
- 文件读取部分:
- 使用
fopen("test.txt", "r")
以读取模式打开文件。 fgets(buffer, sizeof(buffer), fp)
从文件中读取一行内容到buffer
数组中。- 同样使用
fclose(fp)
关闭文件。
- 使用
注意事项
- 在进行文件操作时,务必检查
fopen
函数的返回值,以确保文件能够正常打开。 - 当文件使用完毕后,要及时调用
fclose
函数关闭文件,避免资源泄漏。
练习题 9:预处理指令 - 带参数的宏定义
题目描述
使用带参数的宏定义来计算任意数字的平方。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
int main() {
int num = 0;
printf("输入要平方的数位: ");
scanf("%d", &num);
printf("%d的平方是: %d\n", num, SQUARE(num));
return 0;
}
代码解释
- 宏定义部分:
#define SQUARE(x) ((x) * (x))
定义了一个带参数的宏SQUARE
,用于计算传入参数的平方。注意,宏定义中的参数和表达式都使用括号括起来,这是为了避免在复杂表达式中出现运算符优先级的问题。 - 主函数部分:
- 提示用户输入一个整数。
- 使用
scanf("%d", &num)
读取用户输入的整数。 - 调用宏
SQUARE(num)
计算该整数的平方,并输出结果。
注意事项
- 宏定义只是简单的文本替换,不会进行类型检查和运算优先级的处理,所以在定义宏时要注意括号的使用。
练习题 10:利用指针查找数组的最大值并反转数组
题目描述
本题要求利用指针实现两个功能:一是查找数组中的最大值,二是反转数组元素的顺序。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 函数声明
int* findMax(int arr[], int size);
void reverseArray(int arr[], int size);
int main() {
int arr[] = { 12, 23, 56, 45, 64 };
int size = sizeof(arr) / sizeof(arr[0]);
// 查找数组的最大值
int* maxPtr = findMax(arr, size);
printf("数组中的最大值: %d\n", *maxPtr);
// 输出原数组
printf("原数组: ");
for (int i = 0; i < size; i++) {
printf(" %d ", arr[i]);
}
printf("\n");
// 调用反转函数
reverseArray(arr, size);
// 输出反转后的数组
printf("反转后的数组:");
for (int i = 0; i < size; i++) {
printf(" %d ", arr[i]);
}
printf("\n");
return 0;
}
// 函数定义
int* findMax(int arr[], int size) {
int* max = &arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > *max) {
max = &arr[i];
}
}
return max;
}
void reverseArray(int arr[], int size) {
int temp;
for (int i = 0; i < size / 2; i++) {
temp = arr[i];
arr[i] = arr[size - 1 - i];
arr[size - 1 - i] = temp;
}
}
代码解释
- 查找数组最大值部分:
findMax
函数接受一个整数数组和数组的大小作为参数。- 使用指针
max
初始指向数组的第一个元素。 - 通过遍历数组,比较每个元素与
*max
的大小,若当前元素大于*max
,则将max
指向该元素。 - 最后返回指向最大值的指针。
- 反转数组部分:
reverseArray
函数同样接受数组和数组大小作为参数。- 使用一个临时变量
temp
来交换数组首尾对称位置的元素,只需要遍历数组的前半部分即可完成反转。
注意事项
- 在使用指针时,要确保指针指向有效的内存地址,避免出现空指针引用的问题。
- 反转数组时,循环次数为
size / 2
,这样可以避免重复交换元素。
通过以上几个练习题,我们对 C 语言中的文件读写操作、预处理指令以及指针的应用有了更深入的理解。在实际编程中,要熟练掌握这些知识点,灵活运用它们来解决各种问题。
在学习 C 语言的过程中,通过实际的练习题来巩固知识是非常有效的方法。下面我将分享一些 C 语言的经典练习题,涵盖了登录验证、函数递归、数据查找与排序等多个方面,希望能对正在学习 C 语言的小伙伴们有所帮助。
经典案例分析
练习题 1:连续登录 3 次,锁定账号
题目描述
实现一个简单的登录验证系统,用户有 3 次尝试登录的机会,如果连续 3 次输入的用户名或密码错误,则锁定账号。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define MAX_ATTEMPTS 3
#define USERNAME "admin"
#define PASSWORD "password"
int main() {
char input_username[50];
char input_password[50];
int attempts = 0;
while (attempts < MAX_ATTEMPTS) {
printf("请输入用户名: ");
scanf("%s", input_username);
printf("请输入密码: ");
scanf("%s", input_password);
if (strcmp(input_username, USERNAME) == 0 && strcmp(input_password, PASSWORD) == 0) {
printf("登录成功!\n");
break;
}
else {
attempts++;
printf("用户名或密码错误,你还有 %d 次尝试机会。\n", MAX_ATTEMPTS - attempts);
}
}
if (attempts == MAX_ATTEMPTS) {
printf("账号已锁定,请联系管理员。\n");
}
return 0;
}
代码解释
- 宏定义:使用
#define
定义了最大尝试次数MAX_ATTEMPTS
、正确的用户名USERNAME
和密码PASSWORD
,方便后续修改和维护。 - 循环验证:使用
while
循环,只要尝试次数小于最大尝试次数,就继续提示用户输入用户名和密码。 - 字符串比较:使用
strcmp
函数比较用户输入的用户名和密码是否与预设的一致。 - 锁定账号:当尝试次数达到最大尝试次数时,输出账号锁定的提示信息。
练习题 2:函数:求斐波那契数列前 20 位的值
题目描述
斐波那契数列是指这样一个数列:从第 3 位开始,每一位都是前 2 位的和,即 0, 1, 1, 2, 3, 5, ... 。编写一个函数,求出该数列的前 20 项。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 函数用于求斐波那契数列的第n项
int fibonacci(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 主函数
int main() {
printf("斐波那契数列的前20项为:\n");
for (int i = 0; i < 20; i++) {
printf("%d ", fibonacci(i));
if ((i + 1) % 5 == 0) printf("\n"); // 5个一行
}
printf("\n");
return 0;
}
代码解释
- 递归函数:
fibonacci
函数使用递归的方式计算斐波那契数列的第n
项。当n
小于等于 0 时,返回 0;当n
等于 1 时,返回 1;否则,返回前两项的和。 - 主函数:使用
for
循环调用fibonacci
函数,输出前 20 项的值,并每 5 个一行进行格式化输出。
练习题 3:寻找 500 内的回文数
题目描述
回文数是指正读反读都一样的数,编写一个程序,找出 500 以内的所有回文数,并输出它们的个数。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int is_palindrom(int num) {
int temp = num;
int reversed = 0;
while (temp > 0) {
reversed = reversed * 10 + temp % 10;
temp /= 10;
}
return reversed == num;
}
// 主函数
int main() {
int count = 0;
printf("500内的回文数有:\n");
for (int i = 1; i < 500; i++) {
if (is_palindrom(i)) {
printf("%d \n", i);
count++;
}
}
printf("\n");
printf("500内的回文数的个数为:%d\n", count);
return 0;
}
代码解释
- 判断回文数函数:
is_palindrom
函数通过将数字反转,然后比较反转后的数字与原数字是否相等来判断是否为回文数。 - 主函数:使用
for
循环遍历 1 到 499 的所有数字,调用is_palindrom
函数判断是否为回文数,如果是则输出该数字并计数。
练习题 4:顺序查找算法
题目描述
在数组arrs[] = {11, 23, 32, 22, 14}
中查找某一个元素,并输出其在数组中的位置。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define SIZE 5
// 顺序查找函数
int sequential_search(int arrs[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arrs[i] == target) {
return i;
}
}
return -1;
}
// 主函数
int main() {
int arrs[SIZE] = { 11, 23, 32, 22, 14 };
int target;
printf("请输入要查找的元素: ");
scanf("%d", &target);
int index = sequential_search(arrs, SIZE, target);
if (index != -1) {
printf("找到了,元素下标为: %d\n", index);
}
else {
printf("没有找到\n");
}
return 0;
}
代码解释
- 顺序查找函数:
sequential_search
函数通过遍历数组,依次比较每个元素与目标元素是否相等,如果相等则返回该元素的下标,否则返回 -1。 - 主函数:提示用户输入要查找的元素,调用
sequential_search
函数进行查找,并输出查找结果。
练习题 5:冒泡排序后顺序查找某一个元素
题目描述
先对数组arrs[] = {11, 23, 32, 22, 14}
进行冒泡排序,然后在排序后的数组中查找某一个元素,并输出其在数组中的位置。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define SIZE 5
// 冒泡排序函数
void bubble_sort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 顺序查找函数
int sequential_search(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
int main() {
int arrs[SIZE] = { 11, 23, 32, 22, 14 };
int target;
printf("请输入要查找的元素: ");
scanf("%d", &target);
bubble_sort(arrs, SIZE);
printf("冒泡排序后的数组: ");
for (int i = 0; i < SIZE; i++) {
printf("%d ", arrs[i]);
}
printf("\n");
int index = sequential_search(arrs, SIZE, target);
if (index != -1) {
printf("\n元素 %d 在排序后数组中的下标是 %d\n", target, index);
}
else {
printf("元素 %d 不在数组中\n", target);
}
return 0;
}
代码解释
- 冒泡排序函数:
bubble_sort
函数通过多次比较和交换相邻元素的位置,将数组按升序排序。 - 顺序查找函数:与练习题 4 中的顺序查找函数相同。
- 主函数:先对数组进行冒泡排序,输出排序后的数组,然后调用顺序查找函数进行查找,并输出查找结果。
练习题 6:选择排序后顺序查找某一个元素
题目描述
先对数组arrs[] = {11, 23, 32, 22, 14}
进行选择排序,然后在排序后的数组中查找某一个元素,并输出其在数组中的位置。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define SIZE 5
// 选择排序函数
void selection_sort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
int min_index = i;
for (int j = i + 1; j < size; j++) {
if (arr[j] < arr[min_index]) {
min_index = j;
}
}
if (min_index != i) {
int temp = arr[i];
arr[i] = arr[min_index];
arr[min_index] = temp;
}
}
}
// 顺序查找函数
int sequential_search(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
int main() {
int arrs[SIZE] = { 11, 23, 32, 22, 14 };
int target;
printf("请输入要查找的元素: ");
scanf("%d", &target);
selection_sort(arrs, SIZE);
printf("选择排序后的数组: ");
for (int i = 0; i < SIZE; i++) {
printf("%d ", arrs[i]);
}
printf("\n");
int index = sequential_search(arrs, SIZE, target);
if (index != -1) {
printf("\n元素 %d 在排序后数组中的下标是 %d\n", target, index);
}
else {
printf("元素 %d 不在数组中\n", target);
}
return 0;
}
代码解释
- 选择排序函数:
selection_sort
函数通过每次从未排序部分中选择最小的元素,将其与未排序部分的第一个元素交换位置,逐步将数组按升序排序。 - 顺序查找函数:与练习题 4 中的顺序查找函数相同。
- 主函数:先对数组进行选择排序,输出排序后的数组,然后调用顺序查找函数进行查找,并输出查找结果。
练习题 7:二分查找某一个元素
题目描述
在数组arrs[] = {11, 23, 32, 22, 14}
中查找某一个元素,并输出其在数组中的位置。使用二分查找算法,要求先对数组进行排序。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
// 比较函数,用于 qsort
int compare(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
// 二分查找函数
int binary_search(int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
}
else if (arr[mid] < target) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return -1;
}
int main() {
int arrs[SIZE] = { 11, 23, 32, 22, 14 };
int target;
printf("请输入要查找的元素: ");
scanf("%d", &target);
// 对数组进行排序
qsort(arrs, SIZE, sizeof(int), compare);
printf("排序后的数组: ");
for (int i = 0; i < SIZE; i++) {
printf("%d ", arrs[i]);
}
printf("\n");
int index = binary_search(arrs, SIZE, target);
if (index != -1) {
printf("元素 %d 在排序后数组中的下标是 %d\n", target, index);
}
else {
printf("元素 %d 不在数组中\n", target);
}
return 0;
}
代码解释
- 比较函数:
compare
函数用于qsort
函数,用于比较两个元素的大小,返回值为负数表示第一个元素小于第二个元素,返回值为正数表示第一个元素大于第二个元素,返回值为 0 表示两个元素相等。 - 二分查找函数:
binary_search
函数通过不断将查找范围缩小一半,直到找到目标元素或查找范围为空。 - 主函数:先使用
qsort
函数对数组进行排序,输出排序后的数组,然后调用二分查找函数进行查找,并输出查找结果。
通过这些练习题,我们可以加深对 C 语言的基本语法、函数、数组、排序和查找算法等知识点的理解和掌握。希望大家在学习过程中能够多动手实践,不断提高自己的编程能力。