首页 > 解决方案 > 为什么我的程序允许我更改 C 中 const char 的值?

问题描述

我使用 CodeBlocks for Windows 作为我的 IDE。我的程序有问题,我想了解一下。在我展示的程序中,我将一个变量声明为 achar*并且我的程序将其转换为const char*. 我希望这char*是只读的,但我可以修改,因为我不知道是什么原因。

这是我的代码:

#include <stdio.h>
#include <windows.h>

int main() {
    int i, d;
    char *array[5][5]; // This is the variable that I declare as char*
    for (i = 0; i != 5; i++) {
        for (d = 0; d != 5; d++) {
            array[i][d] = "   "; // I can change its value because it is a char* type variable
        }
    }
    for (i = 1; i != 0; i++) {
        printf("%s %s %s %s %s\n", array[0][0], array[0][1], array[0][2], array[0][3], array[0][4]);
        printf("%s %s %s %s %s\n", array[1][0], array[1][1], array[1][2], array[1][3], array[1][4]);
        printf("%s %s %s %s %s\n", array[2][0], array[2][1], array[2][2], array[2][3], array[2][4]);
        printf("%s %s %s %s %s\n", array[3][0], array[3][1], array[3][2], array[3][3], array[3][4]);
        printf("%s %s %s %s %s\n", array[4][0], array[4][1], array[4][2], array[4][3], array[4][4]);
        array[0][0] = "AAA";  // Again I can change its value
        array[1][0] = "BBB";  // And again...
        Sleep(1000);//This is only to see the results
        system("cls");
        if (i == 5) {
            array[0][0] = strdup(array[1][0]); // I was trying to copy two strings using the strcpy() but the program stopped, and the problem was that the destiny string was a const char* type string and that couldn't be, even though I could change it before  
            strcpy(array[0][0], array[1][0]);
        }
    }
    return 0;
}

标签: cpointersconstantsc-stringsstring-literals

解决方案


char *array[5][5]定义array为指向 modifiable 的可修改 2D 指针数组char。你可以修改它的元素,它们指向的字符串也可以修改。

尽管" "是一个字符串文字,如果不调用未定义的行为就无法修改,但 C 标准不会将其键入为const char[],而是 as ,当存储到 的元素时char [],它会衰减为 a 。char *array

当你strcpy(array[0][0], array[1][0])直接写时,你试图用指向array[0][0]的字符串的内容来修改指向的内存array[1][0]。由于您将字符串文字的地址存储在 中array[0][0],因此您实际上是在尝试修改存储字符串文字的内存,这具有未定义的行为

相反,strdup(array[1][0])分配 指向的字符串的副本array[1][0]并返回一个可以存储到array[0][0]. 下一条语句strcpy(array[0][0], array[1][0]);将原始字符串复制到其副本之上,这是允许的并且没有效果。您可以删除对 的调用strcpy()

建议声明arrayconst char *array[5][5],使strcpy(array[0][0], array[0][1])产生警告,但允许array[0][0] = strdup(array[0][1])。但是请注意,一旦您在这个数组中混合了字符串文字和分配的字符串,您将无法分辨哪些应该被释放,哪些不能。所有分配的内存将在退出时释放,但如果程序运行很长时间并不断修改此数组,则无法进行适当的内存管理将导致内存泄漏和潜在的无限内存使用。

一些编译器提供了将字符串文字类型作为const char[](例如:)的扩展gcc -Wwrite-strings。使用此选项,当您存储" "array[0][0]. 默认情况下使用此设置是一种很好的做法,但可能需要在大型程序中进行大量修改,const在许多地方添加一个称为const中毒的过程。在此过程中发现潜在错误并不罕见。const更一般地说,如果函数定义中的指针参数不直接或间接用于修改它指向的对象,则应该声明它。它可以帮助读者理解代码,也可以帮助编译器生成更好的可执行代码。


推荐阅读