一周前我开始使用C ++进行冒险。我已经阅读了很多关于C ++的内容。 我正在试验以下内容:
char * String1 = "abcdefgh";
然后,我尝试按以下方式修改其值:
String1[2] = 'f';
这导致了UNHANDLED EXCEPTION。 但是以下结果是正确的执行:
char String2[9]="abcdefgh";
String2[7]='s';
我尝试使用DUMPBIN提取有关使用上述代码生成的二进制文件的信息。 DUMPBIN是一个Visual Studio工具。我使用/ ALL选项提取二进制文件中包含的每个信息。
我可以在RAWDATA部分看到两个“abcdefgh”的实例。我理解为什么。
我的问题如下:
1)尽管String1和String2本质上都是指向同一字符序列的两个不同实例的指针,但为什么String1操作不合法呢?
2)我知道编译器生成一个SYMBOL TABLE来映射变量名及其值。有没有可以在Windows操作系统中可视化SYMBOL TABLE的工具?
3)如果我有一个整数数组而不是字符序列,可以在RAWDATA中找到吗?
我还可以在RAWDATA中看到以下内容:
Unknown Runtime Check Error.........
Stack memory around _alloca was corrupted.......
....A local variable was used before it was initialized.........
....Stack memory was corrupted..
........A cast to a smaller data type has caused a loss of data.
If this was intentional, you should mask the source of the cast with the appropriate bitmask.
这些东西如何进入二进制可执行文件?在二进制文件中显示这些消息的目的是什么(显然不可读)?
编辑: 我的问题1)有一个单词INSTANCES,用于表示以下内容:
字符序列“abcdefgh”源自一组非大写的ENGLISH ALPHABETS,即{a,b,...,y,z}。该序列是两次INSTANCIATED并存储在两个存储位置,比如A和B. String1,指向A(假设),String2指向B.在问题中没有概念混淆。
我想要理解的是内存位置A和B的属性的差异,即为什么其中一个是不可变的。
答案 0 :(得分:5)
注意:下面的所有代码都是指函数中的范围。
下面的代码用数据初始化可写缓冲区string2
。编译器生成初始化代码以从只读编译器生成的字符串复制到此缓冲区。
char string2[] = "abcdefgh";
下面的代码将指针存储到string1
中的只读编译器生成的字符串中。字符串的内容位于可执行映像的只读部分。这就是为什么修改它会失败。
char * string1 = "abcdefgh";
您可以通过string1
指向可写缓冲区来使其工作。这可以通过复制字符串来实现:
char * string1 = strdup("abcdefgh");
....
free(string1); // don't forget to free the buffer!
答案 1 :(得分:4)
char * String1 = "abcdefgh";
在C(和C ++)中是const,编译器允许存储固定的const数据但它喜欢,它可能有一个单独的DATA段,它可能有完全const程序存储(在哈佛架构中)
char String2[9]="abcdefgh";
分配9个元素的字符数组,恰好用一些字符串初始化它。你可以用数组做你想做的事。任何其他类型的数组都将以相同的方式存储。
某些运行时错误的错误消息存储在程序数据段中(与原始char *字符串相同)。他们中的一些人喜欢“这个程序需要Windows”显然必须在那里,而不是在操作系统中,因为DOS不知道程序需要更高版本的Windows。但我不确定为什么操作系统不会创建这些特定的运行时错误
答案 2 :(得分:2)
您无法修改字符串文字。字符串文字的类型是
char const[]
,任何修改一个的尝试都是未定义的行为。
并给出了如下声明:
char* s1 = "a litteral";
,编译器确实应该生成警告。隐含的
这里转换为非const不推荐使用,只是引入了
避免破坏现有代码的语言(从一个时代开始
C没有const
)。
在案件中:
char s2[] = "init";
,实际上没有字符串文字。 “字符串文字”实际上是一个
初始化规范,与字符串文字不同,不会出现
记忆中的任何地方编译器使用它来确定s2
的方式
应该初始化,并且恰好相当于:
char s2[] = { 'i', 'n', 'i', 't', '\0' };
(写起来更方便。)
-
一个简短的历史侧面:早期的C没有const
。的类型
字符串文字为char[]
,修改 是合法的。这个领先
一些非常可怕的代码:
char* f() { return "abcd"; }
/* ... */
f()[1] = 'x';
当您下次调用f
时,它返回"axcd"
。一个临时的
它没有源列表中显示的值
不可读代码的方式,C标准委员会决定
这是一个特色,最好不要保留。
答案 3 :(得分:1)
char string[] = "foo"
这将分配一个char数组,并使用值{'f','o','o','\ 0'}初始化它。你可以获得chars的“你自己的”存储空间,你可以修改数组。
char strptr* = "foo"
这会分配一个指针,并将该指针的值设置为包含{'f','o','o','\ 0'}的char数组的地址。您可以根据需要使用指针,但char数组不是。实际上,数组的类型不是char[]
,而const char[]
和strptr
实际上应该被声明为const char*
,这样您就不会错误地尝试修改const数组。
在第一种情况下,"foo"
是一个数组初始值设定项。在第二个中,"foo"
是一个字符串文字。
有关每种情况的确切位置的更具体细节往往未被标准指定。但是,一般来说,char string[] = "foo"
在堆栈上分配char
数组,char strptr* = "foo"
在堆栈上分配char
指针,并(静态地)分配const char
数组在可执行文件的数据部分。
答案 4 :(得分:1)
1)正如c ++标准(2003)(http://www.iso.org/iso/catalogue_detail.htm?csnumber=38110)
所指出的那样1字符串文字是由
包围的字符序列 双引号,可选地以字母L开头,如“......” 或L“......”。不以L开头的字符串文字是 普通字符串文字,也称为窄字符串 文字。普通的字符串文字具有类型“n const的数组” char“和静态存储持续时间( basic.stc ),其中n是大小 如下定义的字符串,并用给定的字符串初始化 字符。以L开头的字符串文字,例如L“asdf”,是 一个宽字符串文字。宽字符串文字的类型为“n的数组” const wchar_t“并且具有静态存储持续时间,其中n是大小 如下定义的字符串,并使用给定的字符初始化 TER值。2是否所有字符串文字都是不同的(即存储 在非重叠对象中)是实现定义的。该 尝试修改字符串文字的效果未定义。
如上所述,它不是非法的,是未定义的行为,所以,使用VS你在Windows上得到一个例外,用g ++你会在linux中得到一个分段错误(基本上他们看起来很相似)
2)您可以使用反汇编程序并检查exe文件的数据部分(有关几个exe文件结构x86 Disassembly/Windows Executable Files的详细信息,请查看此Wiki)
3)是的,它应该在exe文件的.data部分