返回一个char *和一个char 函数的区别是什么?
为什么第一个函数返回string“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; }
第二个函数什么都不返回
第二个函数中的string
数组:
char string[] = "Hello, World!";
具有自动存储时间 。 控制stream从函数返回后不存在。
而在第一个函数中的string
:
char* string = "Hello, World!";
指向具有静态存储持续时间的文字string。 这意味着,从函数返回后string依然存在。 你从函数返回的是一个指向这个文字string的指针。
你需要了解的第一件事情是string文字是真正的只读字符的数组,并且是整个程序的一个生命周期。 这意味着他们永远不会超出范围,他们将永远存在于整个程序的执行过程中。
第一个函数( function1
)做的是返回一个指向这个数组的第一个元素的指针。
第二个函数( function2
)有些不同。 这里variablesstring
是函数内的局部variables 。 因此,一旦函数返回,它将超出范围并不复存在。 有了这个函数,你可以返回一个指向该数组第一个元素的指针,但是这个指针会立即失效,因为它指向的东西不再存在。 解引用它(发生在将它传递给printf
时会发生)将导致未定义的行为 。
在C语言或其他基于堆栈的语言中进行编码时,要记住一个非常重要的事情,那就是当函数返回时,它(和它的所有本地存储)都不见了。 这意味着如果你希望别人能够看到你的方法努力工作的结果,你必须把它放在你的方法停止后仍然存在的地方,这意味着你需要了解C存储的东西和如何。
你可能已经知道一个数组是如何在C中运行的。它只是一个内存地址,它随着对象的大小而增加,你可能也知道C没有进行边界检查,所以如果你想访问一个十的第11个元素元素排列,没有人会阻止你,只要你不写任何东西,没有任何伤害。 你可能不知道的是,C将这个想法扩展到它使用函数和variables的方式。 函数只是按需加载的堆栈中的一块内存区域,其variables的存储区只是该区域的偏移量。 你的函数返回了一个指向局部variables的指针,具体来说就是堆栈中一个保存'Hello World \ n \ 0'的'H'的地址,但是当你调用另一个函数(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'!
我认为这两个函数的返回值都是未定义的,因为它们返回超出范围的数据。
不,情况并非如此。
在函数function1
您正在返回指向string文字的指针。 返回指向string文字的指针很好,因为string文字具有静态存储持续时间 。 但是, 自动局部variables不是这样的。
在函数function2
,数组string
是一个自动局部variables和语句
return string;
返回一个指向自动局部variables的指针。 一旦函数返回,variablesstring
将不再存在。 解引用返回的指针将导致未定义的行为。
我认为这两个函数的返回值都是未定义的,因为它们返回超出范围的数据。
两个函数都返回一个指针。 重要的是所指对象的范围。
在function1
,所指对象是string文字"Hello, World!"
,具有静态存储时间。 string
是指向该string的局部variables,从概念上讲,该指针的副本被返回(实际上,编译器将避免不必要地复制该值)。
在function2
,从概念上讲,所指对象是本地数组string
,它在编译时自动resize以保存string文本(当然包括空终止符),并用string的副本初始化。 该函数将返回一个指向该数组的指针,除了该数组具有自动存储持续时间并因此在退出该函数之后不再存在(这在更熟悉的术语中确实是“超出了范围”)。 由于这是未定义的行为,编译器可能会在实践中做各种事情 。
这是否意味着所有的
char*
都是静态的?
同样,你需要区分指针和指示对象。 指针指向数据; 他们本身并不“包含”数据。
你已经到了一个地步,你应该正确地研究什么数组和指针实际上在C – 不幸的是,这有点乱。 我可以提供的最好的参考是这个问答格式。
"Hello, World!"
是一个string文字,它有一个静态的存储时间,所以问题在别处。 你的第一个函数返回string
的值 ,这很好。 然而,第二个函数返回一个局部variables的地址 ( string
&string[0]
),导致未定义的行为。 你的第二个printf
语句不能打印任何东西,或者“Hello,World!”,或者其他的东西。 在我的机器上,程序只是出现了分段错误。
总是看看你的编译器输出的消息。 对于你的例子, gcc
给出:
file.c:12:12: warning: function returns address of local variable [-Wreturn-local-addr] return string; ^
这几乎是不言自明的。