簡體   English   中英

為什么我的程序讓我更改 C 中的 const char 的值?

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

我使用 Windows 的 CodeBlocks 作為我的 IDE。 我的程序有問題,我想了解一下。 在我展示的程序中,我將一個變量聲明為char*並且我的程序將其轉換為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;
}

char *array[5][5]array定義為指向可修改char的指針的可修改二維數組。 你可以修改它的元素,它們指向的字符串也可以修改。

盡管" "是一個字符串文字,如果不調用未定義的行為就無法修改,但 C 標准不會將其鍵入為const char[] ,而是作為char [] ,當存儲到array的元素時,它會衰減為char *

當你直接寫strcpy(array[0][0], array[1][0])時,你試圖用array[1][0] [ 指向的字符串的內容來修改array[0][0]指向的 memory array[1][0] 由於您將字符串文字的地址存儲在array[0][0]中,因此您實際上是在嘗試修改存儲字符串文字的 memory ,它具有未定義的行為

相反, strdup(array[1][0])分配一個由array[1][0]指向的字符串的副本,並返回一個可以存儲到array[0][0]的指針。 下一條語句strcpy(array[0][0], array[1][0]); 將原始字符串復制到其副本之上,這是允許的並且沒有效果。 您可以刪除對strcpy()的調用。

建議將array聲明為const char *array[5][5] ,使strcpy(array[0][0], array[0][1])產生警告,但允許array[0][0] = strdup(array[0][1]) 但是請注意,一旦您在這個數組中混合了字符串文字和分配的字符串,您將無法分辨哪些應該被釋放,哪些不能。 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.

一些編譯器提供作為const char[]類型字符串文字的擴展(例如: gcc -Wwrite-strings )。 使用此選項,當您將" "存儲到array[0][0]時,您會收到警告。 默認情況下使用此設置是一種很好的做法,但可能需要在大型程序中進行大量修改,在許多地方添加const ,這個過程稱為const中毒 在此過程中發現潛在錯誤並不罕見。 更一般地,如果不直接或間接使用 function 定義中的指針參數來修改它指向的 object,則應將其聲明為const 它可以幫助讀者理解代碼,也可以幫助編譯器生成更好的可執行代碼。

您有一個二維指針數組。

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

所以這些陳述

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

沒有改變最初指向的字符串。 他們更改了作為其值的指針。 現在指針array[0][0]指向文字"AAA" ,而指針array[1][0]指向文字"BBB"

在這份聲明中

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

您再次沒有更改指針array[0][0]指向的字符串文字。 您更改了指針本身的值。 在此語句之后,指針array[0][0]指向由 function strdup返回的動態分配的 memory,並且動態分配的數組包含指針array[1][0]指向的字符串文字的副本。 這就是 function strdup所做的。

這個說法

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

是多余的,因為指針array[0][0]指向的動態分配的數組已經存儲了指針array[1][0]指向的字符串字面量的副本。

請注意,例如這樣的聲明

const char *p = "AAA";

意味着您不能更改作為字符串文字“AAA”的指向 object。 但是您可以更改指針本身的值,例如

p = "BBB"; 

此語句沒有更改字符串文字"AAA" 它改變了指針p的值,該指針現在指向字符串文字"BBB"

如果您希望指針也是不可修改的,那么您應該將其聲明為

const char * const p = "AAA";

在這種情況下,像這樣的聲明

p = "BBB"; 

會產生編譯錯誤。

該數組是一個包含 25 個指向 char 的指針的數組。

數組指向的位置是只讀 memory 中的文字。

以下程序顯示指針是必須更改的。

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

程序的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

我修改了程序以使其可移植。 這並沒有改變基本概念。

注意:對數組 IE“abcd”的裸引用會降級為數組第一個字節的地址。 因此,設置 5x5 數組的嵌套循環正在設置地址,而不是地址指向的值

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM