这行代码如何工作?

4

最近我看了一个人的代码,发现编译器对以下代码没有任何抱怨,也没有运行时错误:

const char *p = "I didn't malloc...";

上面的代码是有效的,但我想知道它是如何工作的。这是我认为正在发生的事情。有人可以确认一下吗?

所以,“我没有malloc…”在编译时静态地分配在堆栈上,并将该地址传递给指针p。类似于静态数组的分配方式。我90%确定这一点,但一些确认会有所帮助。

谢谢。


你正在使用哪个编译器?符合标准的编译器应该会拒绝这个。 - Daniel
1
p的类型应该是char const *,因为该数据段(“通常”)不可写,现今大多数编译器都会发出警告。 - Filip Roséen - refp
2
@Dani 不,它们不应该。这是完全正常的标准 C 和 C++。 - cnicutar
@cnicutar:字符串字面值应该是const char *,所以这一行应该是“赋值丢弃限定符”的错误。 - Daniel
1
@Dani:不是的。在C++03及之前版本中,存在从char const*自动转换为char*的情况(以允许与C的向后兼容性)。我认为这在C++11中已被弃用。但大多数编译器会产生警告。 - Martin York
显示剩余2条评论
5个回答

8
您在指针 p 指向的只读内存中有一个字符串文字 "I didn't malloc..." (确切的位置是由实现定义的)。
需要注意的重要事项是,任何尝试更改此字符串文字都将导致未定义行为
实际上,在C++中声明字符串字面值的方式已被弃用。因此,在C++中,您应该使用const限定符,例如:
const char *p = "I didn't malloc...";

7

这是一个字符串字面量。标准并不知道什么是"堆栈"等 - 这些都是实现细节。所以没有"标准"位置。

通常不在堆栈上。它在一个只读区域中,称为text。它也不是"类似于静态数组的分配方式"。


1
Unix系统中称为“data”的区域不是只读的。现在,只读数据通常在“text”段中,是吗? - Jonathan Leffler
@JonathanLeffler 当然,你是对的。data 是用于可写的已初始化的东西。 - cnicutar

5

内存通常被分配为只读的,任何试图更改 *p 的尝试都是未定义的。
不过,这种分配的内存通常不在堆栈上,而是成为可执行文件的数据段的一部分。


2

字符串字面量"I didn't malloc..."被存储在数据段的只读区域中,而p包含该位置的地址。


2

p将指向在堆栈上分配的只读内存区域。 此外,编译器会自动在字符串末尾添加'\0'字节以进行空值终止。

不使用const是危险的,事实上g++编译器会对以下代码发出警告:

#include <stdio.h>

int main(int argc, const char *argv[])
{
    char *p = "AString8";
    printf("%s\n", p);
    printf("Last char: %c hex: %x\n", p[7], p[7]);
    printf("Last char + 1: %c hex: %x\n", p[8], p[8]);
    return 0;
}

警告:从字符串常量转换为'char *'已被弃用

程序输出:

Last char: 8 hex: 38

Last char + 1:  hex: 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接