【发布时间】:2010-06-02 19:16:49
【问题描述】:
1- 这是如何工作的:
char *ptr = "hi";
现在编译器会将这个字符串放入内存中(我猜是堆栈),并创建一个指向它的指针?这就是它的工作原理吗?
2- 另外如果是在函数中本地创建的,当函数返回时,字符串占用的内存会被释放吗?
3- 最后但同样重要的是,为什么不允许这样做:ptr[0] = 'H';?
【问题讨论】:
-
完成了,我不知道。谢谢
1- 这是如何工作的:
char *ptr = "hi";
现在编译器会将这个字符串放入内存中(我猜是堆栈),并创建一个指向它的指针?这就是它的工作原理吗?
2- 另外如果是在函数中本地创建的,当函数返回时,字符串占用的内存会被释放吗?
3- 最后但同样重要的是,为什么不允许这样做:ptr[0] = 'H';?
【问题讨论】:
1) 字符串not(通常)在堆栈上——它通常位于直接从可执行文件中读取的初始化数据段中。然后将指针初始化为该字符串的地址。
2) 没有。
3) 因为标准说它给出了未定义的行为。考虑一下你是否有这样的事情:
int a() { char *a = "a"; printf("%s\n", a); }
int b() { char *b = "a"; *b = 'b'; }
int main() {
b();
a();
return 0;
}
现在,当您打印出a 时,您希望得到原始值(a)还是更新后的值(b)?编译器可以但不一定共享这样的静态字符串;有些还将整个区域标记为只读,因此尝试对其进行写入会产生异常。
从 C 标准的角度来看,唯一合理的答案是将其称为未定义行为。
【讨论】:
编译器会把字符串“hi”放在内存的某个地方(标准没有强加在哪里),你不知道在哪里,但你必须考虑到它可能放在内存的只读部分(尽管由编译器决定)。然后会创建一个指针,指向内存中这个位置的开始。
不一定会释放内存,因为在大多数情况下,此字符串将驻留在内存的数据部分(与编译指令所在的位置相同)。
这是不允许的,因为标准不保证对这种自动分配的内存块的写访问(参见 1.)。它可能适用于某些系统/平台/编译器,但标准不保证。
【讨论】:
编译器会将指针放到内存中的字符串,并将字符串“hi”的地址放入指针中。字符串本身将在程序的代码图像中。
指针的内存将被释放。
因为您的代码定义的 ptr 指向代码映像中的常量。您不能写入常量。
【讨论】:
你可以更准确、更有力地表达为:
const char *ptr = "hi";
不仅实际情况会在您的代码中表达,而且编译器还将捕获写入ptr 指向的内存的尝试。字符串本身是一个“静态常量”(因此不在堆栈上),指针是一个初始化为字符串地址的变量。
不,只会在堆栈上实例化指针。数据将保留在静态常量内存中(通常作为代码文本段的一部分)。大多数编译器/链接器工具链将匹配常见的字符串,例如,如果您的代码中有多个“hi”实例,它们实际上都会引用同一个实例。
这是未定义的行为。根据文本的存储方式,它可能有效,也可能无效。现代处理器/操作系统经常实施保护机制来保护代码段不被修改和执行;由于此类字符串通常也在代码段中,因此尝试修改字符串可能会导致运行时异常。最好在编译时通过声明指针const 来检测此错误。
如果您碰巧使用的是 16 位 DOS 编译器或没有内存保护的目标,它可能会工作;但是因为我可能会整理常见的字符串,所以您可能正在修改由多个指针引用的字符串。在嵌入式目标上,字符串可能驻留在 ROM 中,在这种情况下,即使访问没有被认为是非法的,它也不会产生任何影响。
【讨论】: