简体   繁体   English

为什么我的程序让我更改 C 中的 const char 的值?

[英]Why does my program let me change a value of a const char in C?

I use CodeBlocks for Windows as my IDE.我使用 Windows 的 CodeBlocks 作为我的 IDE。 I'm having a problem in my program, and I would like to understand it.我的程序有问题,我想了解一下。 In the program that I'm presenting, I declare a variable as a char* and my program turns it into a const char* .在我展示的程序中,我将一个变量声明为char*并且我的程序将其转换为const char* I would expect this char* to be readonly, but I can modify for I don't know what reason.我希望这个char*是只读的,但我可以修改,因为我不知道是什么原因。

Here is my code:这是我的代码:

#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;
}

char *array[5][5] defines array as a modifiable 2D array of pointers to modifiable char . char *array[5][5]array定义为指向可修改char的指针的可修改二维数组。 You can modify its elements and the strings they point to can also be modified.你可以修改它的元素,它们指向的字符串也可以修改。

Although " " is a string literal that cannot be modified without invoking undefined behavior, the C Standard does not type it as const char[] , but as char [] , which decays as a char * when stored to an element of array .尽管" "是一个字符串文字,如果不调用未定义的行为就无法修改,但 C 标准不会将其键入为const char[] ,而是作为char [] ,当存储到array的元素时,它会衰减为char *

When you write strcpy(array[0][0], array[1][0]) directly, you attempt to modify the memory pointed to by array[0][0] with the contents of the string pointed to by array[1][0] .当你直接写strcpy(array[0][0], array[1][0])时,你试图用array[1][0] [ 指向的字符串的内容来修改array[0][0]指向的 memory array[1][0] Since you stored the address of a string literal in array[0][0] , you are in fact trying to modify the memory where the string literal is stored, which has undefined behavior .由于您将字符串文字的地址存储在array[0][0]中,因此您实际上是在尝试修改存储字符串文字的 memory ,它具有未定义的行为

Conversely, strdup(array[1][0]) allocates a copy of the string pointed to by array[1][0] and returns a pointer which can be stored into array[0][0] .相反, strdup(array[1][0])分配一个由array[1][0]指向的字符串的副本,并返回一个可以存储到array[0][0]的指针。 The next statement strcpy(array[0][0], array[1][0]);下一条语句strcpy(array[0][0], array[1][0]); copies the original string on top of its copy, which is allowed and has no effect.将原始字符串复制到其副本之上,这是允许的并且没有效果。 You can remove this call to strcpy() .您可以删除对strcpy()的调用。

It is advisable to declare array as const char *array[5][5] , making strcpy(array[0][0], array[0][1]) produce a warning, but allowing array[0][0] = strdup(array[0][1]) .建议将array声明为const char *array[5][5] ,使strcpy(array[0][0], array[0][1])产生警告,但允许array[0][0] = strdup(array[0][1]) Note however that once you mix string literals and allocated strings in this array, you will have no way to tell which should be freed and which must not.但是请注意,一旦您在这个数组中混合了字符串文字和分配的字符串,您将无法分辨哪些应该被释放,哪些不能。 All allocated memory will be released upon exit, but if the programs runs for a long time and keeps modifying this array, the inability to do proper memory management will force memory leaks and potentially unbounded memory use. All allocated memory will be released upon exit, but if the programs runs for a long time and keeps modifying this array, the inability to do proper memory management will force memory leaks and potentially unbounded memory use.

Some compilers offer as an extension to type string literals as const char[] (eg: gcc -Wwrite-strings ).一些编译器提供作为const char[]类型字符串文字的扩展(例如: gcc -Wwrite-strings )。 With this option, you would get a warning when you store " " into array[0][0] .使用此选项,当您将" "存储到array[0][0]时,您会收到警告。 Using this setting by default is good practice but may require extensive modifications in large programs, adding const in many places, a process called const poisoning .默认情况下使用此设置是一种很好的做法,但可能需要在大型程序中进行大量修改,在许多地方添加const ,这个过程称为const中毒 It is not unusual to discover latent bugs during this process.在此过程中发现潜在错误并不罕见。 More generally, a pointer argument in a function definition should be declared const if it is not used directly or indirectly to modify the object it points to.更一般地,如果不直接或间接使用 function 定义中的指针参数来修改它指向的 object,则应将其声明为const It helps readers understand the code and may also help the compiler produce better executable code.它可以帮助读者理解代码,也可以帮助编译器生成更好的可执行代码。

You have a two-dimensional array of pointers.您有一个二维指针数组。

char * array[5][5];
^^^^^^

So these statements所以这些陈述

    array[0][0] = "AAA";//Again I can change its value
    array[1][0] = "BBB";//And again.

did not change the initially pointed strings.没有改变最初指向的字符串。 They changed the pointers that is their values.他们更改了作为其值的指针。 Now the pointer array[0][0] points to the literal "AAA" while the pointer array[1][0] points to the literal "BBB" .现在指针array[0][0]指向文字"AAA" ,而指针array[1][0]指向文字"BBB"

In this statement在这份声明中

array[0][0] = strdup(array[1][0]); 

you again did not change the string literal pointed to by the pointer array[0][0] .您再次没有更改指针array[0][0]指向的字符串文字。 You changed the value of the pointer itself.您更改了指针本身的值。 After this statement the pointer array[0][0] points to the allocated dynamically memory returned by the function strdup and the dynamically allocated array contains a copy of the string literal pointed to by the pointer array[1][0] .在此语句之后,指针array[0][0]指向由 function strdup返回的动态分配的 memory,并且动态分配的数组包含指针array[1][0]指向的字符串文字的副本。 It is what the function strdup does.这就是 function strdup所做的。

This statement这个说法

strcpy(array[0][0], array[1][0]);

is redundant because the dynamically allocated array pointed to by the pointer array[0][0] already stores a copy of the string literal pointed to by the pointer array[1][0] .是多余的,因为指针array[0][0]指向的动态分配的数组已经存储了指针array[1][0]指向的字符串字面量的副本。

Pay attention to that for example a declaration like this请注意,例如这样的声明

const char *p = "AAA";

means that you may not change the pointed object that is the string literal "AAA".意味着您不能更改作为字符串文字“AAA”的指向 object。 But you may change the value of the pointer itself like for example但是您可以更改指针本身的值,例如

p = "BBB"; 

This statement did not change the string literal "AAA" .此语句没有更改字符串文字"AAA" It changed the value of the pointer p that now points to the string literal "BBB" .它改变了指针p的值,该指针现在指向字符串文字"BBB"

If you want that the pointer also would be non-modifiable then you should declare it like如果您希望指针也是不可修改的,那么您应该将其声明为

const char * const p = "AAA";

In this case a statement like this在这种情况下,像这样的声明

p = "BBB"; 

will generate a compiler error.会产生编译错误。

the array is an array of 25 pointers to char.该数组是一个包含 25 个指向 char 的指针的数组。

the place where the array points is the literal(s) in read-only memory.数组指向的位置是只读 memory 中的文字。

The following program shows that the pointer is what must be changed.以下程序显示指针是必须更改的。

#include <stdio.h>
//#include <windows.h>
//#include <unistd.h>   // sleep()
//#include <stdlib.h>   // system()
#include <string.h>   // strcpy()

int main( void )
{
    int i, d;
    char *array[5][5]; // declare a 2d array of pointers to char

    // initialize the array
    for (i = 0; i != 5; i++) 
    {
        for (d = 0; d != 5; d++) 
        {
            array[i][d] = "abcd"; // I can change its value because it is a char* type variable
            // NO, this is changing where the pointer points
        }
    }

    for (i = 0; i <2; 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]);
        puts("");

        array[0][0] = "defg";  //changes the  the pointer, not the data
    }

    //wait for user input
    int ch;
    while( (ch = getchar()) != '\n' );
    getchar();
    return 0;
}

the output of the program is:程序的output为:

abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd

defg abcd abcd abcd abcd <-- note the changed pointer now points to the new data
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd

I modified the program to make it portable.我修改了程序以使其可移植。 This did not change the underlying concepts.这并没有改变基本概念。

Note: a bare reference to an array IE "abcd" degrades to the address of the first byte of the array.注意:对数组 IE“abcd”的裸引用会降级为数组第一个字节的地址。 Therefore, the nested loop that is setting the 5x5 array is being set with addresses, not the value where the address points因此,设置 5x5 数组的嵌套循环正在设置地址,而不是地址指向的值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的程序给我多余的输出? C程序 - Why does my program give me the excess output? C program 为什么我的 C 程序会给我奇怪的输出? - Why does my C program give me weird outputs? 为什么使用 %u 时我的 char 的二进制值会发生变化? - Why does the binary value of my char change when using %u? 为什么将char传递给函数会更改其在c中的值? - Why does passing a char to a function change it's value in c? 为什么这个C程序不能让我访问内存? - Why won't this C program let me access memory? 为什么C不允许从char **到const char * const *(和C ++)的隐式转换? - Why C doesn't allow implicit conversion from char ** to const char *const * (and C++ does)? 为什么我可以更改const char *变量的值? - Why can I change the value of a const char* variable? 为什么在 C 中使用 int 格式将输入转换为 char 会改变另一个 char 变量的值? - Why in C does taking input using int format to a char change the value of another char variable? 为什么我的C二进制到十进制程序不能返回正确的值? - Why Does My C Binary to Decimal Program Not Return the Correct Value? 为什么我的 C 程序 output 是 memory 地址而不是值? - Why does my C program output the memory address instead of the value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM