所有答案都非常感谢,并且所有那些花时间澄清这些事情的人 - 非常感谢。
我正在学习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";
是指向字符串文字的指针。
为什么它会更新到&#39; World&#39;什么时候它在只读内存?
这是一次全新的重新分配还是什么?
我现在对我对指针的了解非常困惑。我在这里失踪了什么?
答案 0 :(得分:3)
我的理解是
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
的新字符串文字的赋值。
答案 1 :(得分:2)
实际上有两件事正在发生。首先,有字符串文字。您创建了一个零长度字符串""
,它仍然以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
,所以它被认为具有文件范围。 文件范围初始化变量存储在数据段中(更多关于内存布局here)。 (请注意,未初始化的变量可能存储在零段或未初始化的段中,具体取决于架构。)
另一方面,同样取决于架构和平台,文件范围常量可以存储在文本段中的数据段或中,< / strong>单独的常量段或包含程序代码的同一段。
所以你有两个内存位置,可能在不同的程序段中。第一个是您创建的“文字字符串”""
。第二个是您声明的指针变量inp_file
。指针在加载时使用文字字符串的地址进行初始化。
程序运行后,您(可能)执行以下代码:
inp_file = optarg;
这会导致指针变量改变其值。现在,它不是指向您首次创建的文字字符串,而是指向由getopt
库确定的字符串。这可能位于argv
区域中的某个位置,但它可能位于堆上的strdup
ed块中(因为您不知道getopt
如何工作,以及它可能在各种系统)。
请注意:在当天,覆盖用作初始值的“常量”字符串实际上是可能的,也是司空见惯的。您可能会发现仍然执行此操作的旧程序。现代C非常积极地劝阻这一点,但大多数代码都是遗留代码。 ; - )
答案 2 :(得分:0)
您没有更新"hello"
,而是将msg
设置为指向其他字符串"World"
- 它可能会或可能不会strcpy(msg, "World")
代替printf("Before: %p\n", (void*)msg);
在系统设置上,但它肯定是未定义的行为,所以不要编写执行此操作的代码。)
要显示此信息,您可以在printf("After: %p\n", (void*)msg);
行的任意一侧添加msg = "World";
和File.SetAttributes(@"C:\Special", File.GetAttributes(@"C:\Special") |
(FileAttributes.System | FileAttributes.Hidden));
。