C语言作业答案如何正确使用?

99ANYc3cd6
预计阅读时长 48 分钟
位置: 首页 C语言 正文

C语言程序设计 - 作业与答案详解

本指南将按照C语言学习的典型顺序,从基础到进阶,分为多个章节,每个章节包含核心知识点回顾典型作业题详细答案解析

c语言程序设计-作业与答案
(图片来源网络,侵删)

第一章:C语言概述与入门

核心知识点回顾

  1. 程序结构#include(头文件包含)、main()函数(程序入口)、注释( 单行, 多行)。
  2. 基本输入输出printf()(格式化输出)、scanf()(格式化输入)。
  3. 数据类型int(整型)、float(单精度浮点型)、double(双精度浮点型)、char(字符型)。
  4. 变量与常量:变量的定义、初始化和赋值,常量(const)。
  5. 基本运算符:算术运算符(, , , , )、赋值运算符()。

作业题

1:Hello World变体** 编写一个C程序,要求:

  1. 打印出自己的姓名和学号。
  2. 从键盘输入两个整数,计算它们的和并打印出来。

参考答案与解析

#include <stdio.h> // 1. 包含标准输入输出库,这是使用printf和scanf的前提
int main() {
    // 2. 打印个人信息
    // \n 是换行符,使下一次输出在新的一行开始
    printf("姓名: 张三\n");
    printf("学号: 20250001\n");
    // 3. 定义变量
    // int a, b;  // 定义两个整型变量 a 和 b
    // int sum;   // 定义一个整型变量 sum 用来存储和
    // 4. 从键盘输入
    // scanf("%d %d", &a, &b);
    // %d 表示要读取一个整数
    // &a 是取a的地址,scanf需要知道把读到的数据存放到内存的哪个位置
    // 5. 计算并输出
    // sum = a + b;
    // printf("%d + %d = %d\n", a, b, sum);
    // --- 完整代码 ---
    int a, b, sum;
    printf("请输入两个整数,用空格隔开: ");
    scanf("%d %d", &a, &b);
    sum = a + b;
    printf("它们的和是: %d\n", sum);
    return 0; // 6. 程序正常结束,返回0
}

解题思路与易错点

  • 思路:严格按照“包含头文件 -> 定义变量 -> 输入数据 -> 处理数据 -> 输出结果”的步骤来写程序。
  • 易错点
    • 忘记 #include <stdio.h>:编译器会不认识 printfscanf,报错 "implicit declaration of function 'printf'"。
    • scanf 中忘记取地址符 &:例如写成 scanf("%d %d", a, b);,这是最常见的初学者错误,会导致程序运行时崩溃或数据读入错误。
    • 变量未定义就使用:直接使用 sum = a + b; 而没有先定义 int sum;
    • 输出格式错误printf("和是: %d", sum); 漏掉了换行符 \n,导致下一次输出会紧跟在后面。

第二章:选择结构

核心知识点回顾

  1. 关系运算符>(大于)、<(小于)、>=(大于等于)、<=(小于等于)、(等于)、(不等于)。
  2. 逻辑运算符&&(逻辑与)、(逻辑或)、(逻辑非)。
  3. if 语句ifif-elseif-else if-else
  4. switch 语句:用于多分支选择,注意 case 后的值必须是常量或常量表达式,以及 break 的使用。

作业题

2:判断成绩等级** 编写一个程序,要求用户输入一个0-100的整数成绩,然后输出对应的等级:

c语言程序设计-作业与答案
(图片来源网络,侵删)
  • 90-100: A
  • 80-89: B
  • 70-79: C
  • 60-69: D
  • 0-59: E
  • 其他: 输入错误

参考答案与解析 (使用 if-else if)

#include <stdio.h>
int main() {
    int score;
    printf("请输入你的成绩 (0-100): ");
    scanf("%d", &score);
    // 使用 if-else if 结构处理多个区间
    if (score >= 90 && score <= 100) {
        printf("等级: A\n");
    } else if (score >= 80 && score < 90) { // 注意这里的边界条件
        printf("等级: B\n");
    } else if (score >= 70 && score < 80) {
        printf("等级: C\n");
    } else if (score >= 60 && score < 70) {
        printf("等级: D\n");
    } else if (score >= 0 && score < 60) {
        printf("等级: E\n");
    } else {
        // 处理所有不符合0-100范围的情况
        printf("输入错误!成绩应在0到100之间,\n");
    }
    return 0;
}

解题思路与易错点

  • 思路:使用 if-else if-else 链条来依次判断分数所在的区间,判断的顺序很重要,通常从大到小或从小到大。
  • 易错点
    • 逻辑运算符混淆:将 && (与) 写成 (或)。if (score >= 90 || score <= 100) 这个条件永远为真,因为所有成绩都小于等于100。
    • 边界条件错误if (score >= 90) 没有判断 score <= 100,如果用户输入了150,程序也会判定为A级。
    • 与 混淆:在 if 条件中,if (score = 90) 是赋值操作,会把90赋给score,并且表达式的值是90(非零),永远为真,应该使用 if (score == 90) 进行比较。
    • 缺少 else 处理非法输入:如果用户输入了负数或大于100的数,程序没有给出任何提示,这是不健壮的。

第三章:循环结构

核心知识点回顾

  1. for 循环:适用于循环次数已知的情况,结构:for (初始化; 条件判断; 更新)
  2. while 循环:适用于循环次数未知,但循环条件明确的情况,结构:while (条件)
  3. do-while 循环:至少执行一次循环体,然后判断条件,结构:do { ... } while (条件);
  4. breakcontinuebreak 跳出整个循环,continue 跳过本次循环剩余语句,进入下一次循环。

作业题

3:求1到100的和** 使用 for 循环和 while 循环两种方式,计算1到100所有整数的和。

参考答案与解析

#include <stdio.h>
int main() {
    int sum_for = 0;
    int sum_while = 0;
    int i;
    // --- 方法一:使用 for 循环 ---
    // 初始化 i=1, 循环条件 i<=100, 每次循环后 i++
    for (i = 1; i <= 100; i++) {
        sum_for += i; // 等价于 sum_for = sum_for + i;
    }
    printf("使用 for 循环计算 1 到 100 的和是: %d\n", sum_for);
    // --- 方法二:使用 while 循环 ---
    i = 1; // 初始化循环变量
    while (i <= 100) {
        sum_while += i;
        i++; // 别忘了更新循环变量,否则会造成死循环!
    }
    printf("使用 while 循环计算 1 到 100 的和是: %d\n", sum_while);
    return 0;
}

4:判断素数** 编写一个程序,输入一个正整数,判断它是否为素数(质数),素数是指只能被1和它本身整除的大于1的自然数。

参考答案与解析

#include <stdio.h>
#include <math.h> // 为了使用 sqrt() 函数
int main() {
    int num, i;
    int is_prime = 1; // 假设这个数是素数,用1(true)表示,0(false)表示
    printf("请输入一个正整数: ");
    scanf("%d", &num);
    if (num <= 1) { // 1及以下的数不是素数
        is_prime = 0;
    } else {
        // 优化:只需判断到 sqrt(num) 即可
        for (i = 2; i <= sqrt(num); i++) {
            if (num % i == 0) { // 如果能被i整除
                is_prime = 0;   // 则它不是素数
                break;          // 找到一个因子就可以提前结束了
            }
        }
    }
    if (is_prime) {
        printf("%d 是一个素数,\n", num);
    } else {
        printf("%d 不是一个素数,\n", num);
    }
    return 0;
}

解题思路与易错点

  • 思路
    1. 素数定义:核心是“不能被2到num-1之间的任何数整除”。
    2. 算法优化:一个数 num 如果不是素数,那么它必然有一个因子小于或等于 sqrt(num),循环只需从2到 sqrt(num) 即可,大大减少了循环次数。
    3. 标志位法:使用一个变量(如 is_prime)作为标志,先假设是素数,一旦发现能被整除,就修改标志位并退出循环。
  • 易错点
    • 循环范围错误for (i = 2; i < num; i++) 虽然正确,但效率低。for (i = 2; i <= num / 2; i++) 是一个不错的优化。for (i = 2; i <= sqrt(num); i++) 是更优的写法。
    • 边界值处理:忘记处理 num <= 1 的情况,1不是素数。
    • 忘记 break:如果不使用 break,即使找到了因子,循环也会继续执行到 sqrt(num),浪费了计算资源。
    • sqrt(num) 的类型sqrt() 返回 double 类型,iint,比较时会自动转换,但最好写成 i <= (int)sqrt(num) 以保证逻辑清晰。

第四章:数组

核心知识点回顾

  1. 数组定义数据类型 数组名[数组大小];int scores[10];
  2. 数组初始化int a[5] = {1, 2, 3, 4, 5};,部分初始化:int a[5] = {1, 2}; 剩余元素自动为0。
  3. 数组访问:通过下标(索引)访问,从0开始。a[0] 是第一个元素。
  4. 字符串:C语言中字符串是以 '\0' (空字符) 结尾的字符数组。char str[] = "hello";

作业题

5:数组元素排序 编写一个程序,定义一个包含10个整数的数组,从键盘输入这10个数字,然后使用冒泡排序**将它们按从小到大的顺序排序,并输出排序后的结果。

参考答案与解析

#include <stdio.h>
#define N 10 // 定义一个常量N,方便修改数组大小
int main() {
    int arr[N];
    int i, j, temp;
    // 1. 输入数组元素
    printf("请输入 %d 个整数:\n", N);
    for (i = 0; i < N; i++) {
        scanf("%d", &arr[i]);
    }
    // 2. 冒泡排序
    // 外层循环控制排序的趟数
    for (i = 0; i < N - 1; i++) {
        // 内层循环负责每趟中的比较和交换
        // -i 是因为每排序一趟,最大的元素就会冒泡到最后,无需再比较
        for (j = 0; j < N - 1 - i; j++) {
            // 如果前一个数比后一个数大,则交换
            if (arr[j] > arr[j + 1]) {
                // 交换两个变量的值需要借助一个临时变量 temp
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    // 3. 输出排序后的数组
    printf("排序后的数组是:\n");
    for (i = 0; i < N; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

解题思路与易错点

  • 思路
    1. 冒泡排序原理:重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来,遍历数列的工作是重复地进行,直到没有再需要交换的元素为止。
    2. 双层循环:外层循环控制排序的轮数(最多 N-1 轮),内层循环负责在每一轮中进行相邻元素的比较和交换。
  • 易错点
    • 数组下标越界:循环写成 for(i=0; i<=N; i++),会导致访问 arr[N],这是数组之外的内存,会引发程序崩溃或不可预测的错误。
    • 交换逻辑错误temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; 这三句的顺序不能错,如果写成 arr[j] = arr[j+1]; arr[j+1] = arr[j];,两个值都会变成 arr[j+1] 的值,导致数据丢失。
    • 内层循环范围错误:内层循环写成 for(j=0; j<N-1; j++) 虽然能实现排序,但效率不高,优化后的 for(j=0; j<N-1-i; j++) 能减少不必要的比较。

第五章:函数

核心知识点回顾

  1. 函数定义返回类型 函数名(参数列表) { 函数体 }
  2. 函数声明返回类型 函数名(参数列表);,通常放在文件开头。
  3. 函数调用函数名(实际参数);
  4. 参数传递:C语言只有值传递(pass-by-value),实参的值被复制给形参,在函数内部修改形参不会影响实参。
  5. 递归:函数直接或间接地调用自身,必须有递归出口(base case)。

作业题

6:使用函数实现阶乘** 编写一个函数 long factorial(int n),用于计算一个非负整数 n 的阶乘(n!),然后在 main 函数中调用该函数,并打印结果。

参考答案与解析

#include <stdio.h>
// 函数声明
long factorial(int n);
int main() {
    int num;
    long result;
    printf("请输入一个非负整数: ");
    scanf("%d", &num);
    // 调用函数
    result = factorial(num);
    printf("%d! = %ld\n", num, result);
    return 0;
}
// 函数定义:计算阶乘
long factorial(int n) {
    if (n < 0) {
        return -1; // 用-1表示错误输入
    }
    if (n == 0 || n == 1) { // 递归出口/基本情况
        return 1;
    } else { // 递归步骤
        return n * factorial(n - 1);
    }
}

7:使用函数实现数组元素求和** 编写一个函数 int sum_array(int arr[], int size),用于计算一个整数数组的所有元素之和,并返回和,然后在 main 函数中调用该函数。

参考答案与解析

#include <stdio.h>
// 函数声明
int sum_array(int arr[], int size);
int main() {
    int my_array[] = {10, 20, 30, 40, 50};
    // sizeof(my_array) 得到整个数组占用的字节数
    // sizeof(my_array[0]) 得到单个元素占用的字节数
    // 两者相除即可得到数组元素个数
    int array_size = sizeof(my_array) / sizeof(my_array[0]);
    int total_sum;
    total_sum = sum_array(my_array, array_size);
    printf("数组的元素之和是: %d\n", total_sum);
    return 0;
}
// 函数定义:数组求和
// int arr[] 实际上会被编译器处理为 int *arr,即一个指向整型的指针
int sum_array(int arr[], int size) {
    int sum = 0;
    int i;
    for (i = 0; i < size; i++) {
        sum += arr[i];
    }
    return sum;
}

解题思路与易错点

  • 思路
    1. 模块化设计:将一个复杂问题(如阶乘、数组求和)分解成一个独立的、可重用的功能模块(函数)。
    2. 参数传递数组:当函数需要接收一个数组时,形参通常写成 int arr[]int *arr,编译器会将其视为指针,必须额外传递一个参数 size 来告知函数数组的大小,否则函数不知道何时停止遍历。
    • 递归思想:阶乘是递归的经典例子。n! = n * (n-1)!,必须定义一个不需要再递归就能直接返回结果的“基本情况”(0! = 1)。
  • 易错点
    • 忘记函数声明main 函数在 sum_array 函数之后定义,且没有在 main 前声明 sum_array,编译器可能会报错。
    • 递归无出口:写阶乘函数时,如果没有 if (n == 0) return 1; 这句,factorial(n) 会不断调用 factorial(n-1),直到栈溢出(Stack Overflow)。
    • 数组大小未知:在 sum_array 函数内部,如果只写 int sum_array(int arr[]),函数内部无法通过 sizeof(arr) 得到数组大小,sizeof(arr) 会返回指针的大小(通常是4或8字节),而不是数组的大小。

第六章:指针

核心知识点回顾

  1. 指针定义数据类型 *指针名;int *p;p 是一个指向整型数据的指针。
  2. 取地址与解引用& 是取地址运算符, 是解引用(或称间接寻址)运算符。
  3. 指针与数组:数组名 arr 通常会“退化”为其首元素的地址,即 &arr[0]p = arr; 是合法的,*(p+i) 等价于 arr[i]
  4. 指针作为函数参数:通过指针传递,可以实现函数修改外部变量的值(模拟引用传递)。

作业题

8:使用指针交换两个变量的值* 编写一个函数 `void swap(int a, int *b),该函数使用指针来交换两个整数的值,在main` 函数中调用它来验证。

参考答案与解析

#include <stdio.h>
// 函数声明
void swap(int *a, int *b);
int main() {
    int x = 10, y = 20;
    printf("交换前: x = %d, y = %d\n", x, y);
    // 调用函数,传递变量的地址
    swap(&x, &y);
    printf("交换后: x = %d, y = %d\n", x, y);
    return 0;
}
// 函数定义:使用指针交换值
void swap(int *a, int *b) {
    int temp;
    // *a 解引用指针a,得到它指向的变量的值
    temp = *a;
    *a = *b;
    *b = temp;
}

解题思路与易错点

  • 思路
    1. 为什么需要指针:C语言是值传递。swap 函数写成 void swap(int a, int b)main 中的 xy 的值不会被改变,函数内部交换的是 ab(它们是 xy 的副本)。
    2. 如何实现:要修改外部变量,必须传递它的地址,在函数内部,通过解引用操作符 来访问和修改这个地址上存储的值。
  • 易错点
    • 混淆指针和指针指向的值:在 swap 函数内部,操作的是 *a*b,而不是 abab 本身是地址,交换地址没有意义。
    • 忘记解引用:写成 temp = a; a = b; b = temp; 这只是交换了指针 ab 本身,main 函数中的 xy 毫无变化。
    • 函数返回值错误:交换两个变量的值不需要返回值,所以函数返回类型应为 void

第七章:结构体与文件操作

核心知识点回顾

  1. 结构体struct,用于将不同类型的数据组合成一个整体。struct Student { int id; char name[20]; };
  2. 结构体变量定义与访问struct Student s1;,访问成员用 运算符:s1.id
  3. 文件操作
    • fopen(): 打开文件,返回 FILE* 指针。
    • fprintf(), fscanf(): 格式化读写文件。
    • fputc(), fgetc(): 字符读写。
    • fputs(), fgets(): 字符串读写。
    • fclose(): 关闭文件。

作业题

9:学生信息管理(结构体与文件)** 定义一个学生结构体,包含学号(int)、姓名(char[20])和成绩(float),编写程序实现:

  1. 从键盘输入3个学生的信息,并将它们保存到文件 students.txt 中。
  2. 从文件 students.txt 中读取所有学生信息,并打印到屏幕上。

参考答案与解析

#include <stdio.h>
#include <string.h>
// 1. 定义学生结构体
struct Student {
    int id;
    char name[20];
    float score;
};
int main() {
    struct Student stu[3];
    int i;
    // --- 第一部分:写入文件 ---
    printf("请输入3个学生的信息(学号 姓名 成绩):\n");
    FILE *fp_write = fopen("students.txt", "w"); // "w" 表示以写入模式打开文件,如果文件不存在则创建,存在则清空
    if (fp_write == NULL) {
        printf("无法打开文件 students.txt 进行写入!\n");
        return 1;
    }
    for (i = 0; i < 3; i++) {
        scanf("%d %s %f", &stu[i].id, stu[i].name, &stu[i].score);
        // 将学生信息格式化写入文件
        fprintf(fp_write, "%d %s %.2f\n", stu[i].id, stu[i].name, stu[i].score);
    }
    fclose(fp_write); // 写完后关闭文件
    printf("学生信息已成功写入 students.txt\n");
    // --- 第二部分:读取文件 ---
    printf("\n--- 从文件读取的学生信息 ---\n");
    FILE *fp_read = fopen("students.txt", "r"); // "r" 表示以只读模式打开文件
    if (fp_read == NULL) {
        printf("无法打开文件 students.txt 进行读取!\n");
        return 1;
    }
    struct Student read_stu;
    // 循环读取文件,直到文件末尾
    while (fscanf(fp_read, "%d %s %f", &read_stu.id, read_stu.name, &read_stu.score) != EOF) {
        // fscanf 返回成功读取的项数,读到文件末尾时返回 EOF
        printf("学号: %d, 姓名: %s, 成绩: %.2f\n", read_stu.id, read_stu.name, read_stu.score);
    }
    fclose(fp_read); // 读完后关闭文件
    return 0;
}

解题思路与易错点

  • 思路
    1. 数据建模:使用 struct 将一个学生的相关信息(学号、姓名、成绩)封装成一个数据类型,使程序逻辑更清晰。
    2. 文件I/O流程
      • 写入fopen("w") -> 循环 scanf 获取数据 -> 循环 fprintf 写入文件 -> fclose
      • 读取fopen("r") -> 循环 fscanf 读取数据 -> 处理数据 -> fclose
    3. 错误处理:每次 fopen 后都应该检查返回值是否为 NULL,以判断文件是否成功打开,这是健壮编程的重要习惯。
  • 易错点
    • 文件打开模式错误:用 "w" 模式去读取一个不存在的文件会失败,用 "r" 模式去写入一个文件也会失败。
    • 忘记关闭文件:程序结束后,操作系统会回收资源,但养成良好的 fclose 习惯可以确保数据立即从缓冲区写入磁盘,并释放文件句柄资源。
    • fscanf 循环条件错误:读取文件时,应该使用 while (fscanf(...) != EOF) 来判断是否到达文件末尾,而不是 for (i=0; i<3; i++),因为文件中的数据量可能和预期不符。
    • 结构体成员访问错误:访问结构体成员用 运算符,如 stu.id,如果是指向结构体的指针,才用 -> 运算符。

总结与建议

  1. 动手实践:看懂答案和亲手写出代码是两码事,一定要自己动手敲代码、编译、运行、调试。
  2. 理解原理:不要死记硬背代码,对于每个知识点,多问自己几个“为什么”,为什么 scanf&?为什么数组下标从0开始?为什么交换值要用指针?
  3. 调试能力:学会使用编译器的错误提示信息,当程序运行结果不对时,学会使用 printf 在关键位置打印变量值,或者使用专业的调试器单步跟踪,观察程序执行流程和变量变化。
  4. 代码规范:从开始就养成良好的编程习惯,比如有意义的变量名、适当的注释、合理的代码缩进。

希望这份详细的指南能对你的C语言学习有所帮助!祝你学习顺利!

-- 展开阅读全文 --
头像
dede sql文件夹
« 上一篇 今天
织梦PHP查询语句怎么写?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]