[英]returning a pointer to a literal (or constant) character array (string)?
[英]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.