Skip to content

改错题专项训练

C语言改错题常见错误类型 + 15道典型改错题(含解析),针对2026改革新题型

改错题专项训练 · C 语言

背景:2026 年广东专升本计算机真题出现「改错题」信号,2027 届大概率延续。 题型:给出一段有错的 C 代码,要求找出并改正错误(通常 2–3 处)。 注意:不得增行删行、不得改动程序结构,只改指定行或错误处。


① 📊【历年真题考情】

改错题在广东专升本计算机统考中的位置:

项目结论
题型地位2026 改革新增题型("考试形式与内容优化"改革第一年)
真题证据2026 卷面含「改错题」(考生回忆 + 第三方冲刺卷佐证)
未来趋势2027 大概率延续 2026 新题型框架——必须专项准备
考纲说明2026 考纲全解:综合复习第 10 周含"改错题"查漏补缺
关联考点2026 新增"程序运行环境与调试"(编译/链接/运行错误)与改错题强相关

改错题常见出题点(2026 新题型预判):

  • === 混淆、循环边界 < vs <=scanf&
  • 指针未初始化 / 空指针、(*p)++ vs *p++ 优先级
  • 传值调用无法修改实参(需传指针)、字符串 \0 遗漏
  • malloc 忘 free / fopen 忘检查 NULL、数组越界、递归缺边界

🎯 学习目标:学完本章,你能在 2-3 分钟内定位一段错误代码中的全部错误——改错题是最能拉开差距的新题型,会"找错"等于会"写对"。


一、常见错误类型清单

1. 语法错误(编译不通过)

错误示例改正
缺少分号int a = 1int a = 1;
括号不匹配if (a > 5 {if (a > 5) {
关键字拼写错whlie (i < 10)while (i < 10)
主函数写错void mian()int main()void main()
头文件遗漏printf 但没 #include <stdio.h>加上头文件
字符串用单引号char s[] = 'abc';char s[] = "abc";

2. 逻辑错误(编译通过但结果错)

错误示例改正
== 写成 =if (a = 5)if (a == 5)
循环条件错for (i = 1; i <= n; i++) 求 1 到 n-1i < n
数组越界int a[5]; a[5] = 10;a[4] = 10;
字符串无结束符char s[3] = "abc";char s[4] = "abc";
指针未初始化int *p; *p = 5;int a; int *p = &a; *p = 5;
除零错误avg = sum / n; n 可能为 0先判断 n > 0
交换缺中间变量a = b; b = a;t = a; a = b; b = t;

3. 运算符与表达式错误

错误示例改正
自增自减位置错a = i++; 想用新值a = ++i;
整数除法5 / 2 = 2 想要 2.55.0 / 2(float)5 / 2
赋值与比较混淆if (x = 0) 永真(x=0 为假)if (x == 0)
逻辑运算符错if (a > 0 & b > 0)if (a > 0 && b > 0)
位运算与逻辑运算混if (!a & b)看意图,可能是 !a && b

4. 函数与参数错误

错误示例改正
函数未声明就调用先调用后定义加函数原型声明
参数类型不匹配void f(int a); f(3.5);改参数类型或强制转换
返回值类型错int f() { return 3.5; }return (int)3.5; 或改返回类型
传值无法修改实参void swap(int a, int b)用指针 void swap(int *a, int *b)
数组参数写成值void f(int a[10])sizeof(a)数组传参退化为指针,需传长度

5. 指针与数组错误

错误示例改正
指针解引用未初始化int *p; scanf("%d", p);int a; int *p = &a; scanf("%d", p);
数组名当指针修改int a[10]; a++;数组名是常量指针,不能自增
字符指针修改字符串常量char *s = "abc"; s[0] = 'A';用字符数组 char s[] = "abc";
指针越界int a[5], *p = a; p += 5; *p = 1;p += 4 或检查边界
二级指针用错int **p; *p = &a;int *q; p = &q; *p = &a;

6. 字符串处理错误

错误示例改正
strcpy 目标空间不足char d[3]; strcpy(d, "hello");目标数组足够大
== 比较字符串if (s1 == s2)if (strcmp(s1, s2) == 0)
strlen 算上 \0误以为长度含结束符strlen 不计 \0
输入字符串用 &scanf("%s", &s);scanf("%s", s);(数组名已是地址)
gets 不安全gets(s);fgets(s, sizeof(s), stdin);

二、典型改错题 15 道(含解析)

题 1:求 1 到 n 的和

c
#include <stdio.h>

int sum(int n)
{
    int i, s = 0;
    for (i = 1; i < n; i++)   /**** 错误 1 ****/
        s = s + i;
    return s;
}

int main()
{
    int n = 10;
    printf("%d\n", sum(n));
    return 0;
}

错误 1i < ni <= n

解析:求 1 到 n 的和,循环应包含 n。i < n 只加到 n-1,结果为 45 而非 55。


题 2:判断闰年

c
#include <stdio.h>

int isLeap(int year)
{
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)  /**** 错误 1 ****/
        return 1;
    else
        return 0;
}

int main()
{
    int y;
    scanf("%d", y);   /**** 错误 2 ****/
    printf("%d\n", isLeap(y));
    return 0;
}

错误 1:运算符优先级问题。&& 优先级高于 ||,实际逻辑正确,但建议加括号增强可读性:(year % 4 == 0 && year % 100 != 0) || year % 400 == 0。若题目要求改,通常此处逻辑本身正确,重点看错误 2。

错误 2scanf("%d", y)scanf("%d", &y)

解析scanf 需要变量地址,y 是值传递,必须加 &


题 3:交换两个数

c
#include <stdio.h>

void swap(int a, int b)   /**** 错误 1 ****/
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

int main()
{
    int x = 3, y = 5;
    swap(x, y);
    printf("%d, %d\n", x, y);
    return 0;
}

错误 1void swap(int a, int b)void swap(int *a, int *b)

同时函数体内改为:

c
temp = *a;
*a = *b;
*b = temp;

调用改为 swap(&x, &y);

解析:C 语言传值调用,形参改变不影响实参。必须用指针传递地址才能真正交换。


题 4:求字符串长度

c
#include <stdio.h>

int myStrlen(char s[])
{
    int n = 0;
    while (s[n] != '\0')
        n++;
    return n + 1;   /**** 错误 1 ****/
}

int main()
{
    char str[] = "hello";
    printf("%d\n", myStrlen(str));
    return 0;
}

错误 1return n + 1;return n;

解析strlen 不计字符串结束符 \0。循环结束时 n 已经是字符个数("hello" 为 5),不应再加 1。


题 5:数组求最大值

c
#include <stdio.h>

int findMax(int a[], int n)
{
    int i, max = 0;   /**** 错误 1 ****/
    for (i = 1; i < n; i++)
        if (a[i] > max)
            max = a[i];
    return max;
}

int main()
{
    int arr[5] = {-3, -1, -5, -2, -4};
    printf("%d\n", findMax(arr, 5));
    return 0;
}

错误 1max = 0max = a[0],且循环从 i = 1 开始(或 max = a[0]; for(i=0; i<n; i++)

解析:当数组全为负数时,初始化为 0 会导致返回 0 而非真正的最大值(-1)。应初始化为数组第一个元素。


题 6:字符串复制

c
#include <stdio.h>

void myStrcpy(char *dest, char *src)
{
    while (*src != '\0') {
        *dest = *src;
        dest++;
        src++;
    }
    /**** 缺少错误 1 ****/
}

int main()
{
    char d[10], s[] = "abc";
    myStrcpy(d, s);
    printf("%s\n", d);
    return 0;
}

错误 1(遗漏):循环结束后缺少 *dest = '\0';

解析:字符串复制必须在末尾添加结束符 \0,否则 printf("%s") 会输出乱码或越界。


题 7:斐波那契数列

c
#include <stdio.h>

int fib(int n)
{
    if (n == 1 || n == 2)   /**** 错误 1 ****/
        return 1;
    return fib(n - 1) + fib(n - 2);
}

int main()
{
    printf("%d\n", fib(0));
    return 0;
}

错误 1:缺少 n <= 0 的边界处理。若题目要求 fib(0)=0,应加:

c
if (n <= 0) return 0;
if (n == 1 || n == 2) return 1;

解析fib(0) 会无限递归(fib(-1) + fib(-2)...)导致栈溢出。必须处理边界。


题 8:指针求和

c
#include <stdio.h>

int main()
{
    int *p, *q, a = 3, b = 5;
    p = &a;
    q = &b;
    printf("%d\n", p + q);   /**** 错误 1 ****/
    return 0;
}

错误 1p + q*p + *q

解析:两个指针不能直接相加(C 语言不支持指针+指针)。应解引用后相加值,结果为 8。


题 9:结构体输入

c
#include <stdio.h>

struct Student {
    char name[20];
    int age;
};

int main()
{
    struct Student s;
    scanf("%s %d", s.name, &s.age);
    printf("%s, %d\n", s.name, s.age);
    s.name = "Tom";   /**** 错误 1 ****/
    return 0;
}

错误 1s.name = "Tom";strcpy(s.name, "Tom");(需 #include <string.h>

解析:数组名是常量地址,不能直接赋值。字符串复制必须用 strcpy


题 10:冒泡排序

c
#include <stdio.h>

void bubbleSort(int a[], int n)
{
    int i, j, temp;
    for (i = 0; i < n - 1; i++)
        for (j = 0; j < n - 1; j++)   /**** 错误 1 ****/
            if (a[j] > a[j + 1]) {
                temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
}

int main()
{
    int arr[5] = {5, 3, 1, 4, 2};
    bubbleSort(arr, 5);
    for (int i = 0; i < 5; i++)
        printf("%d ", arr[i]);
    return 0;
}

错误 1j < n - 1j < n - 1 - i

解析:冒泡排序每轮将最大元素沉到末尾,下一轮无需再比较已排好的部分。j < n - 1 虽然也能排好序(结果正确),但效率低,标准写法是 j < n - 1 - i。若题目要求优化,此处应改。


题 11:动态内存分配

c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *p = (int *)malloc(10 * sizeof(int));
    int i;
    for (i = 0; i < 10; i++)
        p[i] = i;
    for (i = 0; i < 10; i++)
        printf("%d ", p[i]);
    /**** 缺少错误 1 ****/
    return 0;
}

错误 1(遗漏):缺少 free(p);

解析malloc 分配的堆内存必须手动释放,否则内存泄漏。良好习惯是用完即 free


题 12:字符统计

c
#include <stdio.h>

void count(char *s, int *upper, int *lower)
{
    *upper = 0;
    *lower = 0;
    while (*s != '\0') {
        if (*s >= 'A' && *s <= 'Z')
            (*upper)++;   /**** 注意此处 ****/
        else if (*s >= 'a' && *s <= 'z')
            *lower++;
        s++;
    }
}

int main()
{
    char str[] = "Hello World";
    int u, l;
    count(str, &u, &l);
    printf("upper=%d, lower=%d\n", u, l);
    return 0;
}

注意(*upper)++ 是正确的(先解引用再自增)。如果写成 *upper++ 则是错误的(指针后移而非值自增)。

若题目中写的是 *upper++ → 改为 (*upper)++

解析*upper++ 等价于 *(upper++),是指针移动,不是对指向的值加 1。必须加括号。


题 13:二维数组传参

c
#include <stdio.h>

void printMatrix(int **a, int row, int col)   /**** 错误 1 ****/
{
    int i, j;
    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++)
            printf("%d ", a[i][j]);
        printf("\n");
    }
}

int main()
{
    int mat[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    printMatrix(mat, 3, 4);
    return 0;
}

错误 1int **aint a[][4]int (*a)[4]

解析:二维数组名传给函数时退化为「指向一维数组的指针」,不是二级指针。必须指定第二维大小。


题 14:递归求阶乘

c
#include <stdio.h>

int factorial(int n)
{
    if (n == 0)
        return 0;   /**** 错误 1 ****/
    return n * factorial(n - 1);
}

int main()
{
    printf("%d\n", factorial(5));
    return 0;
}

错误 1return 0;return 1;

解析:0! = 1(数学定义),不是 0。若返回 0,整个阶乘结果都为 0。


题 15:文件读写

c
#include <stdio.h>

int main()
{
    FILE *fp;
    char ch;
    fp = fopen("test.txt", "r");   /**** 错误 1(潜在) ****/
    while ((ch = fgetc(fp)) != EOF)
        putchar(ch);
    fclose(fp);
    return 0;
}

错误 1(潜在):缺少文件打开失败检查。应加:

c
if (fp == NULL) {
    printf("文件打开失败\n");
    return 1;
}

解析:若文件不存在,fopen 返回 NULL,后续 fgetc(NULL) 会导致程序崩溃。必须检查返回值。


三、改错题解题步骤

  1. 先通读:理解程序整体功能(求什么/做什么)
  2. 编译检查: mentally 编译,找语法错误(分号、括号、关键字)
  3. 逻辑跟踪:用简单输入手动执行,看哪一步结果不对
  4. 边界检查:n=0、n=1、空字符串、全负数等边界情况
  5. 指针检查:是否初始化、是否越界、解引用是否正确
  6. 函数检查:参数类型、返回值、传值 vs 传址
  7. 确认修改:只改错误处,不增删行,不改程序结构

四、改错题高频考点排名

  1. === 混淆(出现率最高)
  2. 循环边界 <=<
  3. 指针未初始化 / 空指针
  4. 字符串结束符 \0 遗漏
  5. 传值调用无法修改实参(需传指针)
  6. 数组越界
  7. scanf&
  8. 字符串比较用 == 而非 strcmp
  9. 递归缺少边界条件
  10. 二维数组传参类型错误

五、补充:编译/链接/运行错误综合改错题(2026 新考点联动)

2026 考纲新增"程序运行环境与调试"考点,改错题常结合"判断错误发生在哪个阶段"来考。

题 16:判断错误阶段(2026 单选8 风格)

下列说法错误的是(  )

A. 缺少分号通常属于编译错误 B. 数组越界通常在运行阶段才被发现 C. 链接错误常见于符号找不到定义 D. 除以 0 属于编译错误

👆 点击展开答案与解析

答案:D

  • 除以 0 是运行错误(运行时才崩溃),不是编译错误
  • A 对:缺分号破坏语法 → 编译阶段报错
  • B 对:数组越界编译期发现不了,运行时崩
  • C 对:函数只有声明没有定义 → 链接时符号找不到

口诀:语法找编译,符号找链接,越界/除零找运行


题 17:综合改错(语法 + 逻辑 + 运行时错误)

下面的程序想统计 1 到 n 之间能被 3 整除的数之和,但有多处错误,请全部改正。

c
#include <stdio.h>

int main()
{
    int n, sum, i;
    scanf("%d", n);          /**** 错误 1 ****/
    sum = 0
    for (i = 1; i < n; i++)  /**** 错误 2 ****/
        if (i % 3 = 0)       /**** 错误 3 ****/
            sum = sum + i;
    printf("sum=%d\n", sum);
    return 0;
}
👆 点击展开答案与解析

错误 1scanf("%d", n)scanf("%d", &n)(scanf 需要变量地址)

错误 2sum = 0sum = 0;(缺少分号 → 编译错误)

错误 3i < ni <= n(应包含 n,否则漏掉 n 本身 → 逻辑错误)

错误 4if (i % 3 = 0)if (i % 3 == 0)= 赋值 vs == 比较 → 逻辑错误)

逐错误定位

  1. scanf("%d", n):缺 &,n 是值 → 运行时可能崩溃/输入无效
  2. sum = 0 缺分号:编译错误
  3. i < n:求 1~n 应 <=,漏最后一项 → 逻辑错误
  4. i % 3 = 0= 把 i%3 赋值为 0(恒真/恒假错),应为 == → 逻辑错误

改正后

c
#include <stdio.h>

int main()
{
    int n, sum, i;
    scanf("%d", &n);
    sum = 0;
    for (i = 1; i <= n; i++)
        if (i % 3 == 0)
            sum = sum + i;
    printf("sum=%d\n", sum);
    return 0;
}

验证:输入 10 → 3+6+9 = 18


⚠️ 改错题高频扣分坑(新增模块)

#陷阱错误做法正确做法关联章节
1只找一个错改完一个就交卷改错题通常 2-3 处,改完再复查一遍全章
2增行删行加一行辅助代码只改错误处,不得增删行、改结构全章
3== 写成 =if (a = 5) 以为比较if (a == 5)1.4 选择结构
4循环边界i < n 求 1~ni <= n(含 n)1.5 循环
5scanf 缺 &scanf("%d", n)scanf("%d", &n)1.3 顺序
6指针忘初始化int *p; *p = 5;int a; int *p = &a; *p = 5;1.8 指针
7(*p)++ 写错写成 *p++ 想自增值(*p)++ 改值;*p++ 移指针1.8 指针
8字符串忘 \0手动复制后不加结束符循环后补 *dest = '\0';1.6 数组
9传值想改实参swap(int a,int b) 想交换传指针 swap(int *a,int *b)1.7/1.8
10malloc/fopen 忘检查直接使用返回值先判 NULL1.8 指针
11递归忘边界fib(0) 无限递归if (n <= 0) return 0;1.7 函数
12main 写错void mian()int main()1.1 概述

2027 备考指南 · 知识点笔记 · 回真题总览

仅供个人学习 · 考生回忆版 · 非考试院原卷