从函数返回char *和char []有什么区别?

时间:2017-09-07 07:38:09

标签: c string pointers

为什么第一个函数返回字符串" Hello,World"但第二个函数什么也没有返回。我认为两个函数的返回值都是未定义的,因为它们返回的数据超出了范围。

#include <stdio.h>
// This successfully returns "Hello, World"
char* function1()
{
    char* string = "Hello, World!";
    return string;
}
// This returns nothing
char* function2()
{
    char string[] = "Hello, World!";
    return string; 
}

int main()
{
    char* foo1 = function1();
    printf("%s\n", foo1); // Prints "Hello, World"
    printf("------------\n");
    char* foo2 = function2(); // Prints nothing
    printf("%s\n", foo2);
    return 0;
}

6 个答案:

答案 0 :(得分:66)

  

第二个函数不返回任何内容

第二个函数中的string数组:

char string[] = "Hello, World!";

自动存储时间。控制流从函数返回后不存在。

而第一个函数中的string

char* string = "Hello, World!";

指向文字字符串,其静态存储持续时间。这意味着,从函数返回后,字符串仍然存在。你从函数返回的是指向这个文字字符串的指针。

答案 1 :(得分:26)

您需要了解的第一件事是字符串文字实际上是一个只读字符数组,其生命周期为完整程序。这意味着它们永远不会超出范围,它们将始终存在于整个程序的执行过程中。

第一个函数(function1)的作用是返回指向这样一个数组的第一个元素的指针。

使用第二个函数(function2)时,事情会略有不同。这里变量string是函数中的局部变量。因此,一旦函数返回,它将超出范围并停止存在。使用此函数,您将返回指向该数组的第一个元素的指针,但该指针将立即变为无效,因为它将指向不再存在的内容。取消引用它(当您将其传递给printf时会发生这种情况)将导致undefined behavior

答案 2 :(得分:7)

在使用C语言或其他基于堆栈的语言进行编码时要记住的一件非常重要的事情是,当函数返回时,它(及其所有本地存储)都消失了。这意味着如果你希望其他人能够看到你的方法的结果很难,你必须把它放在你的方法停止后仍然存在的地方,这样做意味着你需要了解C存储东西的方式和方式。

你可能已经知道数组如何在C中运行。它只是一个内存地址,它以对象的大小递增,你可能也知道C不会进行边界检查,所以如果你想访问第11个元素一个十元素阵列,没有人会阻止你,只要你不试图写任何东西,没有伤害。您可能不知道的是C将这个想法扩展到它使用函数和变量的方式。函数只是堆栈上的内存区域,按需加载,其变量的存储只是偏离该位置。你的函数返回了一个指向局部变量的指针,特别是堆栈中一个包含&#39; H&#39; &#39; Hello World \ n \ 0&#39;但是当你调用另一个函数(print方法)时,print方法会重用内存来完成它所需要的操作。你可以很容易地看到这一点(不要在生产代码中这样做!!!)

char* foo2 = function2(); // Prints nothing
ch = foo2[0];  // Do not do this in live code!
printf("%s\n", foo2);  // stack used by foo2 now used by print()
printf("ch is %c\n", ch);  // will have the value 'H'!

答案 3 :(得分:5)

  

我认为两个函数的返回值都是未定义的,因为它们返回的数据超出了范围。

没有。事实并非如此。

在函数function1中,您将返回指向字符串文字的指针。返回指向字符串文字的指针很好,因为字符串文字具有静态存储持续时间。但自动局部变量并非如此。

在函数function2中,数组string是一个自动局部变量和语句

return string; 

返回指向自动局部变量的指针。函数返回后,变量string将不再存在。取消引用返回的指针将导致未定义的行为。

答案 4 :(得分:1)

"Hello, World!"是一个字符串文字,具有静态存储持续时间,所以问题出在其他地方。你的第一个函数返回string,这很好。然而,第二个函数返回局部变量的地址string&string[0]相同),导致未定义的行为。你的第二个printf语句可以不打印任何内容,或者#34; Hello,World!&#34;或其他完整的内容。在我的机器上,程序只会出现分段错误。

始终查看编译器输出的消息。对于您的示例,gcc给出:

file.c:12:12: warning: function returns address of local variable [-Wreturn-local-addr]
    return string; 
           ^

这几乎是不言自明的。

答案 5 :(得分:0)

  

我认为两个函数的返回值都是未定义的,因为它们返回的数据超出了范围。

两个函数都返回一个指针。重要的是指示物的范围

function1中,指示对象是字符串文字"Hello, World!",它具有静态存储持续时间。 string是一个指向该字符串的局部变量,从概念上讲,返回该指针的副本(实际上,编译器将避免不必要地复制该值)。

function2中,从概念上讲,指示对象是本地数组string,它已经自动调整大小(在编译时)足够大以容纳字符串文字(当然包括空终止符) ),并用字符串的副本进行了初始化。函数返回指向该数组的指针,除了该数组具有自动存储持续时间,因此在退出该函数后不再存在(它确实是“超出范围”,在更熟悉的术语中)。由于这是未定义的行为,编译器may in practice do all sorts of things

  

这是否意味着所有char*都是静态的?

同样,您需要区分指针和指示对象。指针指向数据;他们自己并不“包含”数据。

你已经达到了应该正确研究C中实际存在的数组和指针的程度 - 不幸的是,这有点乱。我可以随意提供的最佳参考是this,采用Q&amp; A格式。