簡體   English   中英

為什么我要更新指向(常量)字符串文字的指針?

[英]Why can I update a pointer to a (constant) string literal?

高度贊賞所有答案,並感謝所有致力於澄清這些問題的人- 非常感謝

我正在學習C,並且剛剛結束了有關指針的章節。 在這本書中,我正在閱讀示例代碼,這讓我感到非常困惑。

示例代碼的一部分:

...

 1  char *inp_file = "";
 2  char *out_file = "";
 3  char ch;
 4  
 5  while ( ( ch = getopt( argc, argv, "i:o:" )) != EOF )
 6  {
 7      switch( ch )
 8      {
 9          case 'i':
10              inp_file = optarg;
11              break;
12          case 'o':
13              out_file = optarg;
14              break;
15  
16          default:
17              fprintf( stderr, "Unknown option: '%s'/n", optarg );
18              return 2;
19      }
20  }
21  
22  argc -= optind;
23  argv += optind;

...

我的理解是char *inp_file = ""char *out_file = ""是指向字符串文字的指針。

他們指向哪里? 考慮到它是一個空的“”

將它們存儲在只讀存儲器中時,如何更新它們(第10、13行)?

char *pointer; char *pointer = "";


此外,我嘗試了這一點,它奏效了。

#include <stdio.h>

int main( int argc, char *argv[] )
{
    char *msg = "Hello";

    msg = "World";

    printf("%s\n", msg );// Prints 'World'
}

我100%確定char *msg = "Hello"; 是指向字符串文字的指針。

為什么它在只讀存儲器中時會更新為“ World”?

是完全重新分配還是什么?

我現在真的很困惑我對指針的了解。 我在這里想念什么?

我的理解是char *inp_file = ""char *out_file = ""是指向字符串文字的指針。

對,他們是。

他們指向哪里?

他們指向一個空字符串文字。

char *pointer; char *pointer = "";

char *pointer; 是一個未初始化的指針,而char *pointer = ""; 初始化的。 ""的類型為const char[1] ,元素為'\\0'

為什么它在只讀存儲器中時會更新為"World"

char *msg = "Hello"; 相當於

char const *msg = "Hello";  

這意味着不得修改字符串文字msg指向的字符串,但此約束位於字符串文字上,而不是指向字符串文字的指針。 msg可以修改。

是完全重新分配還是什么?

msg = "World"; 是將新字符串文字分配給指針msg

實際上有兩件事在發生。 首先,有字符串文字。 您創建了一個零長度字符串"" ,它仍然是NUL終止的,因為所有C字符串都是NUL終止的-這就是您知道結尾的位置。

因此,您將擁有如下所示的內存塊:

Memory loc'n:  Contents
BASE+0x0000:  # start of string
BASE+0x0000:  '\0'  # end of string

也就是說,一個包含“無字符”的內存塊,后跟一個尾隨的NUL字節以標記字符串的結尾。

該數據通常被認為是“恆定的”。 它可能會或可能不會存儲在“常量數據”中。 這取決於鏈接器,操作系統等。

但是,這只是“常量字符串文字”。 您的代碼還有第二部分:

char *inp_file = "";

您已經聲明了一個指向常量字符串文字的指針 該指針是指針大小的對象(如果具有32位地址空間,則為4字節;如果具有64位地址空間,則為8字節;如果具有不同或混合的地址空間,則為其他大小)並包含常量字符串文字的第一個字節的內存地址

Memory loc'n:      Contents
PTR_BASE+0x0000:   (BASE+0x0000)
PTR_BASE+0x0008:   ...

因為您在任何函數之外都聲明了inp_file ,所以它被認為具有file scope 文件范圍初始化變量存儲在數據段中 (有關內存布局的更多信息,請參見此處 )。 (請注意,根據體系結構,未初始化的變量可以存儲在零段或未初始化的段中 。)

另一方面,再次取決於體系結構和平台,文件范圍常量可以存儲在數據段 文本段中,可以是單獨的常量段也可以是包含程序代碼的同一常量段。

因此,您有兩個存儲位置,可能在不同的程序段中。 第一個是您創建的“文字字符串” "" 第二個是您聲明的指針變量inp_file 指針在加載時使用文字字符串的地址進行初始化。

程序運行后,您(可能)執行如下代碼:

inp_file = optarg;

這將導致指針變量更改其值。 現在,它指向由getopt庫確定的字符串,而不是指向您首先創建的文字字符串。 這可能在argv區域中的某處,但可能在堆的strdup ed塊中(因為您不知道getopt工作原理,以及它在各種系統上的作用)。

請注意:過去,實際上有可能並且很普遍的方法來覆蓋用作初始值的“常量”字符串。 您可能會找到仍然可以執行此操作的舊程序。 現代C在阻止這種行為方面非常積極,但是大多數代碼都是遺留代碼。 ;-)

您沒有更新"hello" ,而是將msg設置為指向不同的字符串"World" -取而代之(取決於系統設置,它可能會也可能不會起作用strcpy(msg, "World") (取決於系統設置,但絕對是未定義的)行為,因此請勿編寫執行此操作的代碼)。

為了顯示這一點,您可以添加一個printf("Before: %p\\n", (void*)msg); printf("After: %p\\n", (void*)msg); 在您的msg = "World";任一側msg = "World"; 線。

暫無
暫無

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

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