2011-11-15 35 views
4

我正在使用主要使用C++但使用c风格字符串的现有代码的项目。采取以下内容:基本c风格的字符串内存分配

#include <iostream> 
int main(int argc, char *argv[]) 
{ 
    char* myString = "this is a test"; 
    myString = "this is a very very very very very very very very very very very long string"; 
    cout << myString << endl; 
    return 0; 
} 

这编译和运行正常,输出是长字符串。

但我不明白为什么它的作品。我的理解是,

char* myString 

是一个指向的内存大到足以容纳字符串“这是测试”的区域。如果是这样的话,那么我怎么能够在同一个位置存储更长的字符串呢?我希望这样做会导致崩溃,因为试图将一个长的字符串塞入为较短字符串留出的空间。

显然有这么欣赏我理解这个任何帮助,这是怎么回事这里的基本误解。

+0

不应该这样被标记为“C++”和“c-字符串”,而不是“C”和“串”?这个问题是关于C++,而不是关于C. – 2011-11-15 20:56:43

+0

@WTP - 你是对的,我已经相应地编辑了标签。 – TheOx

回答

14

你不改变内存的内容,你正在改变指针的值,指向不同的内存区域,其中包含"this is a very very very very very very very very very very very long string"

注意,仅char* myString用于指针(通常是4或8个字节)分配足够的字节。当你做char* myString = "this is a test";时,实际发生的是在你的程序开始之前甚至开始,编译器在可执行映像中分配了空间,并把"this is a test"放在那个内存中。然后当你做char* myString = "this is a test";它实际上做的只是为指针分配足够的字节,并使指针指向它在编译时已经在可执行文件中分配的内存。

所以,如果你想图:

char* myString = "this is a test"; 

(allocate memory for myString) 

       ---> "this is a test" 
      /
myString--- 

        "this is a very very very very very very very very very very very long string" 

然后

myString = "this is a very very very very very very very very very very very long string"; 

        "this is a test" 

myString--- 
      \ 
       ---> "this is a very very very very very very very very very very very long string" 
+2

啊!这就说得通了。所以当这种情况发生时,分配给原来的“这是一个测试”字符串的内存是否会自动释放? – TheOx

+2

@ DTJon不,它仍然存在于可执行文件中,并且会在整个程序中不会改变。这就是为什么你永远不能做'char * a =“某事”; a [1] ='f';'因为'a'指向一些_read-only_内存,并且你不允许改变它的内容。 –

+2

好吧,只读内存是一个impl。细节,但它是UB修改文字。 –

2

你有const char[n]类型的两个字符串文字。这些可以被分配到类型为char*的变量,这只不过是指向char的指针。每当你声明一个指向T类型的变量时,你只是声明指针,而不是它指向的内存。

编译器预留内存。既文字和你只是把你的指针变量,并在这些文字指向它一前一后。字符串文字是只读的,它们的分配由编译器负责。通常它们被存储在可执行映像中的受保护的只读存储器中。字符串文字通常具有与程序本身相同的生命周期。现在

,这将是UB如果你试图修改文本的内容,但你不知道。为了防止你自己试图修改错误,你应该明智地将你的变量声明为const char*

+0

不是'char const [x]'而不是'const char *'类型的文字吗?或者我对这两者感到困惑。 –

+0

@你是对的。当然数组会衰减到指针,所以几乎没有什么区别。 –

1

字符串字面不需要配置 - 它们被原样保存,可以直接使用。基本上,myString是一个指向一个字符串文字的指针,并被改为指向另一个字符串文字。

0

char*指一个指针,其保持字符的存储器块。

C风格字符串函数获取指向字符串开头的指针。他们假设有一个以0空字符结尾的字符序列(\ n)。

因此,运算符实际上所做的是从第一个字符位置开始循环,直到找到空字符。

5

内存中有两个字符串。首先是"this is a test",可以说它从地址0x1000开始。第二个是"this is a very very ... test",它从地址0x1200开始。

通过

char* myString = "this is a test"; 

你箱子一个名为myString和地址为0x1000分配给它的变量。然后,通过

myString = "this is a very very ... test"; 

您分配0x1200。通过

cout << myString << endl; 

你只是在打印开始从0x1200字符串。

2

在程序执行过程中,会分配一个包含“this is a test”的内存块,并将该块内存中第一个字符的地址分配给myString变量。在下一行中,分配了一个单独的包含“this is very very ...”的内存块,现在将该块内存中的第一个字符的地址分配给myString变量,替换它用于的地址将新地址存储到“非常非常长”的字符串中。

只是为了说明,假设的存储器的第一个块看起来像这样:

[T] [H] [I] [秒] [] [I] [s]的[] [A] [] [t] [e] [s] [t] 并且让我们假设这个序列/字符数组中的第一个't'字符的地址是0x100。 因此,在myString变量的第一次赋值之后,myString变量包含地址0x100,该地址指向“this is a test”的第一个字母。

然后,一个完全不同的存储器块包含:

[T] [H] [I] [秒] [] [I] [s]的[] [A] [] [V] [E ] [r] [r] [y] ... 让我们只是说这个第一个't'字符的地址是0x200。 所以在myString变量的第二次赋值之后,myString变量NOW包含地址0x200,它指向“这是一个非常非常非常非常......”的第一个字母。由于myString只是一个指向字符的指针(因此:“char *”是它的类型),它只存储一个字符的地址;它并不关心阵列应该有多大,它甚至不知道它指向一个“阵列”,只是它正在存储一个字符的地址......

例如,你可以合法地做到这一点:

char myChar = 'C'; 
/* assign the address of the location in 
    memory in which 'C' is stored to 
    the myString variable. */ 
    myString = &myChar; 

希望这已经够清楚了。如果是这样,upvote /接受答案。如果不是,请评论,以便我澄清。