为什么我可以更新指向(常量)字符串文字的指针?
Why can I update a pointer to a (constant) string literal?
All answers are highly appreciated, and to all those devoting their time clarifying these things - thank you very much .
我正在学习 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'?
这是一个全新的重新分配还是什么?
我现在对指针的了解真的很困惑。我在这里错过了什么?
My understanding is that char *inp_file = ""
and char *out_file = ""
are pointers to string literals.
是的,他们是。
Where are they pointing to ?
它们指向空字符串文字。
Is char *pointer;
same as char *pointer = "";
?
没有。 char *pointer;
是未初始化的指针,而 char *pointer = "";
是已初始化的指针。 ""
属于 const char[1]
类型,具有元素 '[=19=]'
.
Why it gets updated to "World"
when it's in read-only memory ?
char *msg = "Hello";
等同于
char const *msg = "Hello";
意思是msg
指向的字符串字面量不能被修改,但是这个约束是针对字符串字面量的,而不是指向字符串字面量的指针。 msg
可以修改。
Is it a complete new reassignment or what ?
msg = "World";
是对指针 msg
.
的新字符串文字赋值
您没有更新 "hello"
,您正在将 msg
设置为指向不同的字符串,"World"
- 改为 strcpy(msg, "World")
可能会也可能不会(取决于系统设置,但它绝对是未定义的行为,所以不要编写执行此操作的代码)。
为了显示这一点,您可以在 msg = "World";
行的任一侧添加 printf("Before: %p\n", (void*)msg);
和 printf("After: %p\n", (void*)msg);
。
实际上有两件事正在发生。首先是字符串文字。您创建了一个零长度字符串 ""
,它仍然以 NUL 结尾,因为所有 C 字符串都是以 NUL 结尾的——这就是您知道结尾在哪里的方式。
所以你有一块内存看起来像这样:
Memory loc'n: Contents
BASE+0x0000: # start of string
BASE+0x0000: '[=10=]' # end of string
即包含"no characters"的内存块,后跟一个尾随的NUL字节来标记字符串的结尾。
那个数据一般被认为是 "constant." 它可能存储也可能不存储在 "constant data." 这取决于链接器, OS 等
但是, 这只是 "constant string literal." 您的代码还有第二部分:
char *inp_file = "";
您已经声明了一个指向常量字符串文字的指针。该指针是一个指针大小的对象(如果您有 32 位地址 space,则为 4 字节;如果您有 64 位地址,则为 8 字节 space;如果您有不同或混合地址 space) 并包含常量字符串文字的第一个字节的 内存地址 。
Memory loc'n: Contents
PTR_BASE+0x0000: (BASE+0x0000)
PTR_BASE+0x0008: ...
因为您在任何函数之外声明了 inp_file
,它被认为具有 文件范围。 文件范围初始化变量存储在数据段中(更多关于内存布局here)。 (请注意,未初始化的变量可能存储在零段或未初始化的段中,具体取决于体系结构。)
另一方面,再次取决于体系结构和平台,文件范围常量可能存储在数据段或中文本段,单独的常量段或包含程序代码的同一段。
所以你有两个内存位置,可能在不同的程序段中。第一个是您创建的"literal string",""
。第二个是你声明的指针变量,inp_file
。指针在加载时使用文字字符串的地址进行初始化。
一旦你的程序是 运行,你(可能)执行的代码是:
inp_file = optarg;
这导致指针变量改变它的值。现在,它不再指向您最初创建的文字字符串,而是指向由 getopt
库确定的字符串。这可能在 argv
区域的某处,但它可能在堆上的 strdup
ed 块中(因为您不知道 getopt
是如何工作的,以及它可能在各种系统)。
请注意:在过去,覆盖用作初始值的 "constant" 字符串实际上是可能且司空见惯的。您可能会发现仍然执行此操作的旧程序。现代 C 非常积极地阻止这种情况,但大多数代码都是遗留代码。 ;-)
All answers are highly appreciated, and to all those devoting their time clarifying these things - thank you very much .
我正在学习 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'?
这是一个全新的重新分配还是什么?
我现在对指针的了解真的很困惑。我在这里错过了什么?
My understanding is that
char *inp_file = ""
andchar *out_file = ""
are pointers to string literals.
是的,他们是。
Where are they pointing to ?
它们指向空字符串文字。
Is
char *pointer;
same aschar *pointer = "";
?
没有。 char *pointer;
是未初始化的指针,而 char *pointer = "";
是已初始化的指针。 ""
属于 const char[1]
类型,具有元素 '[=19=]'
.
Why it gets updated to
"World"
when it's in read-only memory ?
char *msg = "Hello";
等同于
char const *msg = "Hello";
意思是msg
指向的字符串字面量不能被修改,但是这个约束是针对字符串字面量的,而不是指向字符串字面量的指针。 msg
可以修改。
Is it a complete new reassignment or what ?
msg = "World";
是对指针 msg
.
您没有更新 "hello"
,您正在将 msg
设置为指向不同的字符串,"World"
- 改为 strcpy(msg, "World")
可能会也可能不会(取决于系统设置,但它绝对是未定义的行为,所以不要编写执行此操作的代码)。
为了显示这一点,您可以在 msg = "World";
行的任一侧添加 printf("Before: %p\n", (void*)msg);
和 printf("After: %p\n", (void*)msg);
。
实际上有两件事正在发生。首先是字符串文字。您创建了一个零长度字符串 ""
,它仍然以 NUL 结尾,因为所有 C 字符串都是以 NUL 结尾的——这就是您知道结尾在哪里的方式。
所以你有一块内存看起来像这样:
Memory loc'n: Contents
BASE+0x0000: # start of string
BASE+0x0000: '[=10=]' # end of string
即包含"no characters"的内存块,后跟一个尾随的NUL字节来标记字符串的结尾。
那个数据一般被认为是 "constant." 它可能存储也可能不存储在 "constant data." 这取决于链接器, OS 等
但是, 这只是 "constant string literal." 您的代码还有第二部分:
char *inp_file = "";
您已经声明了一个指向常量字符串文字的指针。该指针是一个指针大小的对象(如果您有 32 位地址 space,则为 4 字节;如果您有 64 位地址,则为 8 字节 space;如果您有不同或混合地址 space) 并包含常量字符串文字的第一个字节的 内存地址 。
Memory loc'n: Contents
PTR_BASE+0x0000: (BASE+0x0000)
PTR_BASE+0x0008: ...
因为您在任何函数之外声明了 inp_file
,它被认为具有 文件范围。 文件范围初始化变量存储在数据段中(更多关于内存布局here)。 (请注意,未初始化的变量可能存储在零段或未初始化的段中,具体取决于体系结构。)
另一方面,再次取决于体系结构和平台,文件范围常量可能存储在数据段或中文本段,单独的常量段或包含程序代码的同一段。
所以你有两个内存位置,可能在不同的程序段中。第一个是您创建的"literal string",""
。第二个是你声明的指针变量,inp_file
。指针在加载时使用文字字符串的地址进行初始化。
一旦你的程序是 运行,你(可能)执行的代码是:
inp_file = optarg;
这导致指针变量改变它的值。现在,它不再指向您最初创建的文字字符串,而是指向由 getopt
库确定的字符串。这可能在 argv
区域的某处,但它可能在堆上的 strdup
ed 块中(因为您不知道 getopt
是如何工作的,以及它可能在各种系统)。
请注意:在过去,覆盖用作初始值的 "constant" 字符串实际上是可能且司空见惯的。您可能会发现仍然执行此操作的旧程序。现代 C 非常积极地阻止这种情况,但大多数代码都是遗留代码。 ;-)