2017-02-26 36 views
0

所有的答案都非常感谢,并致力于所有那些致力于澄清这些事情的人 - 非常感谢你为什么我可以更新指向(常量)字符串文字的指针?

我在学习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";是一个指向字符串常量。

为什么它在只读存储器被更新为'世界'?

它是一个完全新的重新分配或什么?

我现在对我所知道的指针非常困惑。我在这里错过了什么?

+0

请打开所有编译器警告。 –

+0

'inp_file'和'out_file'是一些指向'char'块的指针。这个块如何存在是无关紧要的 - 它可以是一个字符串文字,它可以分配在堆上,它可以是堆栈中的本地数组。 'inp_file'可以同时指向一个字符串字符串,另一个时间指向一个堆块,第三次指向一个堆栈分配的数组。 –

+2

指针在只读存储器中不是*,而是指向它的字符串。 –

回答

2

我的理解是,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

+0

我应该避免以这种方式分配数据吗? – HelloWorld

+0

我看不出有什么不好。 – haccks

0

你没有更新"hello",要设置msg指向一个不同的字符串,"World" - 它可能会或可能无法正常工作要做strcpy(msg, "World")代替(根据系统设置,但它肯定是不确定的行为,所以不写代码这是做到这一点)。

为了表明这一点,您可以在msg = "World";系列的两侧添加一个printf("Before: %p\n", (void*)msg);printf("After: %p\n", (void*)msg);

2

实际上有两件事情正在进行。首先,有字符串文字。你创建了一个零长度的字符串"",它仍然是NUL终止的,因为所有的C字符串都是NUL终止的 - 这就是你如何知道结束的地方。

所以,你有一个内存块,看起来像这样:

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

也就是说,包含“无字”的内存块,然后尾随NULL字节来标记字符串的结束。

该数据通常被认为是“不变的”。它可能会或可能不会被存储在“常量数据”中。这取决于链接器,操作系统等。

但是,即只有“常量字符串文字”。还有第二个部分代码:

char *inp_file = ""; 

你已经宣布指针到常量字符串文字。该指针是一个指针大小的对象(如果您有32位地址空间,则为4字节,如果您有64位地址空间,则为8字节,如果地址空间不同,则为其他大小)并且包含常量字符串文字的第一个字节的内存地址

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

因为你宣布inp_file以外的任何功能,它被认为具有文件范围。 A 文件范围初始化变量存储在数据段(更多关于内存布局here)。(请注意,未初始化的变量可以被存储在一个零段未初始化段,这取决于体系结构。)

在另一方面,这也取决于架构和平台,一个文件范围恒定可以被存储在数据段中的文本段中,既可以是单独的常量段,也可以是包含程序代码的同一段。

所以你有两个内存位置,可能在不同的程序段。第一个是你创建的“文字串”,""。第二个是你声明的指针变量,inp_file。指针在加载时使用文字字符串的地址进行初始化。

一旦你的程序正在运行,你(可能)执行代码,上面写着:

inp_file = optarg; 

引起指针变量来改变其值。现在,它不是指向您最初创建的文字字符串,而是指向由getopt库确定的字符串。这可能位于argv区域,但它可能位于堆上的strdup版块(因为您不知道getopt如何工作,以及它在各种系统上可能会做什么)。

请注意:回到当天,覆盖用作初始值的“常量”字符串实际上是可行的,并且很平常。您可能会发现仍然会这样做的旧程序。现代C在阻止这种情况下非常积极,但大多数代码都是遗留代码。 ;-)

+0

不错的链接,谢谢。你认为我应该如何分配数据?第一个字符串文字(“”)内存明智会发生什么?被删除或... – HelloWorld

+0

它不会被删除。它被“抛弃”。一些编译器可以合并常量,包括字符串常量。所以你的两个'... =“”'声明可能指向相同的字节或不同的字节。 –

相关问题