在C语言中使用const char *返回字符串

6
我试图理解以下字符串传递如何适用于我的错误字符串。这个示例是我从一个更大的源代码中制作的。
我的问题是,为什么我不需要为包含我的错误消息的字符数组专门分配内存?我认为我需要为字符串分配一些内存,并使用err指针指示该内存的开始。
这与它是一个“const char *”有关还是因为我在stderr打印?
我可能没有恰当表达问题,这就是为什么搜索没有帮助我理解这个问题的原因。
const char * my_function(int a)
{
     if (a != 1)
         return "a doesn't equal 1!"
     else
         return NULL;

}

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    return 0;
}

2
请参见:https://dev59.com/dW445IYBdhLWcg3we6V9 - flyx
6个回答

10

所有的字符串文字都是在编译时分配的。当您的程序启动时,它们已经驻留在程序内存的只读部分中;它们不会在运行时分配。您可以把它们看作是常量字符数组。和任何 const 变量一样,它们在整个程序执行期间保持有效。


所有的字符串字面值都是在编译时分配的。- 对我来说,这是所有答案中最有帮助的部分。 - Markus
3
所有字符串文字都是在编译时分配的。 这种措辞真的正确吗?我认为没有任何东西是在编译时分配的。 如果它在编译时分配,那么什么时候被释放呢? 这句话的翻译可以为:"所有字符串字面量都在编译时分配。这个说法真的正确吗?我认为在编译时不会分配任何东西。如果字符串字面量是在编译时分配的,那么何时会被释放?" - Kolyunya
如果您很挑剔,那么请关注链接时间。字符串字面量通常放置在一个名为.rodata的内存段中。 - Lundin
这是因为你子程序中的字符串存储在共享段(只读)中,可以在子程序退出后返回。如果你将其定义为char str[]="your string",你将无法返回该值,因为它在堆栈上“分配”。堆栈指针将在子例程结束时恢复。所以@Ludin的答案在这里只是部分的。 - TwoCode

3
请注意,你的main()函数总是会返回1。
int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    return 0;
}

return 1的缩进好像是在if (err)下面,但实际上不是这样。你真正拥有的是:

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
    return 1;
    return 0; # Never gets executed.
}

你想要的是:

您所需要的是:

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err) {
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    }
    return 0;
}

这就是为什么我始终在代码块周围使用大括号的原因,即使它们并不是必需的。


3

字符串字面量被分配为具有静态存储期的const char数组,因此它们将在程序的整个生命周期内存在。它们所在的作用域是无关紧要的,它们始终具有静态存储期。

这意味着您可以获取它们的地址(如果您在任何地方返回字符串字面量或将其存储在const char *变量中,则会隐式发生),而不必担心结果指针的生命周期。字符串字面量的存储将永远不会用于其他用途。


2

您正在返回字符串字面量。它被保存在静态内存中,但像任何其他字符串一样具有地址。因此,您可以随时引用该地址。问题在于,如果您尝试更改字符串字面量,则可能会出现未定义的行为。


1
这是因为字符串存储在程序的数据部分。当你输入“a doesn't equal 1!”时,内存被分配,并将该值写入其中。您的函数仅返回指向该内存片段的指针,fprintf很高兴从中读取。

那么分配了多少内存?只有足够返回我的字符串的内存吗? - Markus
如果我有另一个函数返回到相同地址的const char *,但是它更长呢? - Markus
只需足够的字符串,查看生成的汇编代码即可了解其工作原理。 - Bart Friederichs
我不明白你的第二个问题,你说的“但是更长”是什么意思?另一个返回相同指针的函数将可以正常工作。您可以在printf函数中使用%p来查看指针实际指向的地址。 - Bart Friederichs
从Lundin的评论中,我现在明白了所有字符串字面量都是在程序运行时分配内存。当我将指针传回不同的字符串字面量时,我没有改变该地址上的内存,而是返回一个指向只读内存中不同位置的指针。 - Markus
1
@Markus 当程序编译时,字符串字面量会被“分配”(运行时,操作系统会将代码和数据复制到内存中,基本上为它们分配实际的内存)。它们存储在二进制文件中。您可以在Unix上使用类似strings的工具来查看它们。 - Bart Friederichs

0
不要过于乐观。这是因为你子程序中的字符串存储在共享段(只读)中,可以在子程序退出后返回。如果你将其定义为char str[]="your string",你将无法返回该值,因为它是在堆栈上“分配”的。堆栈指针将在子程序结束时恢复。

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