C-为什么我可以将指针更新为(常数)字符串文字



所有答案都高度赞赏,以及所有用于澄清这些事情的人 - 非常感谢

我正在学习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("%sn", 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]具有元素''

为什么在仅阅读内存中更新为"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:  ''  # end of string

也就是说,一个包含"无字符"的内存块,然后是尾随的nul字节来标记字符串的末端。

通常认为数据是"恒定的"。它可能会或不可存储在"恒定数据"中。这取决于链接器,操作系统等

但是,只是"常数字符串"。您的代码有第二部分:

char *inp_file = "";

您已将指针宣布为常数字符串字面。该指针是一个指针大小的对象(如果有32位地址空间,则为4个bytes,如果您有64位地址空间,则有8个bytes,如果您有不同的或混合的地址空间,则有些其他尺寸)并包含常数字符串文字的第一个字节的内存地址

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

由于您在任何功能之外声明了inp_file,因此被认为具有文件范围。A 文件范围初始化变量存储在数据段中(此处有关内存布局的更多信息)。(请注意,非初始化的变量可以存储在零段>或>非专业化段,取决于架构。)

另一方面,再次根据体系结构和平台,文件范围常数可以存储在数据段中,/strong>单独的常数段或包含程序代码的相同的段。

因此,您有两个内存位置,可能在不同的程序段中。第一个是您创建的"文字字符串" ""。第二个是您声明的指针变量inp_file。指针在加载时间用文字字符串的地址初始化。

您的程序运行后,您(可能)执行代码:

inp_file = optarg;

导致指针变量更改其值。现在,它没有指向您首先创建的文字字符串,而是指向由getopt库确定的字符串。这可能在argv区域中的某个地方,但是它可能位于堆上的strdup ED块中(因为您不知道getopt的工作原理以及在各种系统上的作用)。

请注意:回到当天,覆盖用作初始值的"恒定"字符串实际上是可能的,而且很普遍。您可能会发现仍然可以执行此操作的旧程序。Modern C对劝阻这一点非常积极,但大多数代码是旧版代码。; - )

您不更新"hello",您将msg设置为指向另一个字符串,"World"-它可能会或可能无法使用strcpy(msg, "World")(取决于系统设置),但绝对是未定义的行为,所以不要编写执行此操作的代码)。

为了显示此信息,您可以在msg = "World";行的两侧添加printf("Before: %pn", (void*)msg);printf("After: %pn", (void*)msg);

最新更新