C中的空指针与字符串字面值

3

使用ARM和C编译器,我能够成功地编译和运行以下代码:

static char * myString = 0;

void myfunc(int x){

   if (x <= 0)
       myString = "Hello World";
   else 
       myString = "This is a different string with a different length";

}

int main(){

    myfunc(-1);
    printf("%s\n", myString);
    myfunc(2);
    printf("%s\n", myString);
}

为什么这个代码可以工作?

指针不应该是一个空指针吗?

至少,字符串常量应该被分配在只读内存位置上吧?

编辑:这是一个C++编译器

编辑2:为什么字符串常量在myfunc函数已经结束后仍然存在于静态作用域中?字符串常量不是在栈上声明的吗?它们何时被释放?

谢谢!


1
你能澄清一下你的问题吗?"myString"不再是NULL的原因是你已经对它进行了赋值。 - Robᵩ
字面量可能被分配在只读内存中。第一个的形式类型是 const char[12]。你可以将它的地址赋给 char*,因为这在 C 中曾经是允许的。但正确的做法是使用 const char* - Bo Persson
1
字符串字面量是静态的,并且随着程序的运行而存在。 - Bo Persson
谢谢大家的帮助。我现在更好地理解字符串字面值了。 - J T
6个回答

7
两个字符串都分配在只读内存中,且完全不同。但你使用同一个指针来指向它们中的每一个...这有什么难以理解的呢?
记住,char* 只是一个指针。它是可变的(非const)。
char* p = 0;
p = "Hello"; //OK
p = "Jo" //OK;
p[0] = 'X' //OOPS, now THIS is bad (undefined behavior)

经过您的编辑:

不,字符串字面值具有静态存储期(与所有其他字面值不同),它们不会在堆栈上创建。 它们将存在于程序终止之前。


1
这里存在未定义的行为,是因为C兼容性胜过了const正确性。在一个虚构的类型安全世界中,将字符串字面值分配给char*将会违反编译时const限制。 - Seva Alekseyev

3
如果您要声明
char const *MyString = 0;  

如果您使用const指针,那么当您尝试重新分配时会遇到麻烦。字符串字面值是常量。

       .section        .rodata
.LC0:
        .string "Hello World"
        .align 8
.LC1:
        .string "This is a different string with a different length"
        .text

文字字符串数据被组装在只读数据段中。

2

常量字符串通常在程序的“数据段”中创建,指向它们的指针始终有效(字符串“对象”在程序生命周期内有效)。因此,字面字符串不会在堆栈上创建。

我相当确定C语言中的语义是明确定义的。

编码愉快。


1

虽然如此,但是你将一个指针分配给它,所以它指向两个字符串数组中的一个。


0

一开始它是一个空指针。但是你自己在myfunc函数内明确更改了该指针并使其变为非空。

在第一次调用myfunc时,你明确将指针指向字符串字面值"Hello World"。此后,指针当然不再为空。

字符串字面值确实分配在只读内存位置(至少在概念上是这样)。但是,在C和C++中,你可以使用char *指针指向字符串字面值(即不需要const char *)。只要你不尝试修改字面值,就可以使用char *指针简单地指向字符串字面值,因此你的代码没有尝试修改任何内容,所以是可以的。

C和C++中的字符串字面值具有静态存储期。因此,它们不会被“分配在堆栈上”。它们总是分配在静态内存中,这意味着它们永远存在-只要你的程序在运行。

P.S. 为了更完整地回答你的问题,你必须解释为什么你希望指针保持为空。

P.P.S. int main,而不是void main

0

myString 是一个指针变量,你有意将它设置为指向其中一个字符串常量存储的内存。


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