C语言常量报错是什么原因?

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

下面我将详细解释这类错误的各种情况、原因以及如何解决。

c语言出错constant
(图片来源网络,侵删)

错误的核心原因

编译器告诉你:"嘿,你正在试图给一个只读的内存区域赋值,这是不允许的!"

这通常发生在以下几种情况:

  1. 使用了 const 关键字修饰的变量。
  2. 直接使用了字面量(如数字、字符串)。
  3. 在函数参数中错误地使用了指针。

最常见的错误 - 修改 const 变量

这是最直接、最常见的 "constant expression" 错误。

错误示例

#include <stdio.h>
int main() {
    const int MAX_AGE = 100; // MAX_AGE 被声明为一个常量
    printf("MAX_AGE is: %d\n", MAX_AGE);
    // 尝试修改一个 const 变量
    MAX_AGE = 101; // 这里会出错!
    printf("Now MAX_AGE is: %d\n", MAX_AGE);
    return 0;
}

编译器错误信息 (以GCC为例)

test.c: In function 'main':
test.c:8:9: error: assignment of read-only variable 'MAX_AGE'
     8 |     MAX_AGE = 101;
       |         ^~~~~~

错误分析:

c语言出错constant
(图片来源网络,侵删)
  • const int MAX_AGE = 100; 告诉编译器,MAX_AGE 是一个常量,它的值在初始化后不能被改变。
  • MAX_AGE = 101; 这行代码试图改变 MAX_AGE 的值,编译器在编译时就能发现这个违规操作,并报错。

如何解决

  1. 移除修改操作:如果你确实需要一个在程序运行过程中不会改变的值,那就不要去修改它。

    const int MAX_AGE = 100;
    // ... 程序中使用 MAX_AGE,但不要修改它
  2. 使用普通变量:如果你这个值确实需要被修改,那就不要使用 const 关键字。

    int max_age = 100;
    max_age = 101; // 这样就没问题了

在函数参数中错误地修改了 const 指针指向的内容

这种情况稍微复杂一些,是初学者容易混淆的地方。

错误示例

#include <stdio.h>
// 这个函数的意图是打印一个数组的元素
void print_array(const int *arr, int size) {
    // arr 是一个指向 const int 的指针
    // 这意味着我们不能通过 arr 来修改它所指向的整数值
    for (int i = 0; i < size; i++) {
        // 尝试修改指针指向的值
        arr[i] = 0; // 这里会出错!
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main() {
    int my_array[] = {1, 2, 3, 4, 5};
    print_array(my_array, 5);
    return 0;
}

编译器错误信息

test.c: In function 'print_array':
test.c:10:13: error: assignment of read-only location '*arr'
    10 |         arr[i] = 0;
       |             ^~~~

错误分析:

  • const int *arr 的含义是:arr 是一个指针,它指向一个 const int(一个整型常量)。
  • 这保证了指针所指向的数据是只读的,目的是为了安全。print_array 函数只需要读取数组内容,不需要修改它,所以使用 const 是一个好习惯。
  • arr[i] 实际上是 *(arr + i) 的语法糖,意思是“获取 arr 指向的值”,试图给这个值赋 0,就等于修改了一个常量,所以编译器报错。

如何解决

  1. 移除修改操作:如果函数确实不需要修改数据,那就不要修改,这是最安全的做法。

    void print_array(const int *arr, int size) {
        for (int i = 0; i < size; i++) {
            // 只读,不修改
            printf("%d ", arr[i]);
        }
    }
  2. 修改函数签名:如果函数确实需要修改传入的数组,那么应该在声明指针时去掉 const

    // 函数签名改为
    void modify_array(int *arr, int size) {
        for (int i = 0; i < size; i++) {
            arr[i] = 0; // 现在就没问题了
        }
    }

试图修改一个字面量

这种情况比较少见,但也是可能的,字面量是直接写在代码中的值,如 10'a'"hello"

错误示例

int main() {
    // 尝试修改一个整型字面量
    10 = 20; // 绝对会出错!
    // 尝试修改一个字符串字面量(在C语言中,字符串字面量通常存储在只读内存区)
    char *str = "hello";
    str[0] = 'H'; // 在很多编译器和系统上,这会导致段错误或运行时崩溃
                  // 一些编译器可能会在编译时给出警告或错误
    return 0;
}

编译器错误信息

test.c: In function 'main':
test.c:4:5: error: expression is not assignable
    4 |     10 = 20;
       |     ^~

错误分析:

  • 10 是一个字面量,它没有内存地址,只是一个值,你不能给一个值“赋值”,这是没有意义的。
  • 字符串字面量 "hello" 通常被放在程序的只读数据段,试图修改它会导致未定义行为,通常是程序崩溃。

如何解决

  • 不要这样做! 字面量就是用来表示固定值的,不能修改,如果需要一个可变的字符串,请使用字符数组。
    // 正确做法
    char str[] = "hello"; // str 是一个字符数组,存储在栈上,是可修改的
    str[0] = 'H'; // 现在可以安全地修改
    printf("%s\n", str); // 输出 "Hello"

switch 语句中使用非常量表达式

switch 语句的 case 标签必须是整型常量表达式,这意味着它必须在编译时就能计算出值,并且不能是变量。

错误示例

#include <stdio.h>
int main() {
    int choice = 2;
    const int C = 5;
    switch (choice) {
        case 1:
            printf("One\n");
            break;
        case choice: // 错误!choice 是一个变量
            printf("Two\n");
            break;
        case C: // 这是允许的!C 是一个 const 变量,它的值在编译时是已知的
            printf("Five\n");
            break;
        default:
            printf("Other\n");
    }
    return 0;
}

编译器错误信息

test.c: In function 'main':
test.c:11:10: error: case label does not reduce to an integer constant
   11 |         case choice:
      |              ^~~~~~

错误分析:

  • case 标签需要编译器在编译代码时就确定好跳转的地址,而 choice 是一个运行时才能确定值的变量,编译器无法处理。
  • const int C = 5; 之所以可以,是因为 C 的值在编译时是固定的(即使你不能通过代码修改它),编译器可以用 5 来代替它。

如何解决

  • 使用 if-else if-else 结构:当条件不是常量时,这是唯一的选择。
    if (choice == 1) {
        printf("One\n");
    } else if (choice == 2) {
        printf("Two\n");
    } else if (choice == C) { // C 仍然可以使用
        printf("Five\n");
    } else {
        printf("Other\n");
    }
错误场景 错误原因 解决方案
修改 const 变量 变量被声明为只读,但尝试赋新值。 不要修改它。
如果需要修改,去掉 const 关键字。
修改 const 指针指向的内容 指针指向的数据是只读的,但尝试通过指针修改它。 不要修改它。
如果需要修改,去掉指针声明中的 const
修改字面量 字面量(如 10, "hello")是代码中的固定值,没有内存地址或位于只读区。 不要修改! 使用变量(如 int a = 10;char str[] = "hello";)来存储需要变化的值。
switch 中使用变量作为 case case 标签必须是编译时就能确定的整型常量表达式。 使用 if-else if-else 结构。
确保使用的是真正的常量(如 #defineconst 变量)。

当你遇到 "constant" 相关的错误时,首先找到错误行号,然后检查该行是否属于以上四种情况之一,问题都能迎刃而解。

-- 展开阅读全文 --
头像
dede文章如何快速生成二维码?
« 上一篇 今天
C语言unsigned字节
下一篇 » 今天

相关文章

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

目录[+]