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

时间:2021-11-03 20:11:59

This question already has an answer here:

这个问题已经有了答案:

Why does the first function return the string "Hello, World" but the second function returns nothing. I thought the return value of both of the functions would be undefined since they are returning data that is out of scope.

为什么第一个函数返回字符串“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 个解决方案

#1


63  

the second function returns nothing

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

The string array in the second function:

第二个函数中的字符串数组:

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

has automatic storage duration. It does not exist after the control flow has returned from the function.

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

Whereas string in the first function:

而第一个函数中的字符串:

char* string = "Hello, World!";

points to a literal string, which has static storage duration. That implies that, the string still exists after returning back from the function. What you are returning from the function is a pointer to this literal string.

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

#2


25  

The first thing you need to learn about strings is that a string literal is really an array of read-only characters with a lifetime of the full program. That means they will never go out of scope, they will always exist throughout the execution of the program.

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

What the first function (function1) does is returning a pointer to the first element of such an array.

什么第一个函数function1()返回一个指向数组的第一个元素。

With the second function (function2) things are a little bit different. Here the variable string is a local variable within the function. As such it will go out of scope and cease to exist once the function returns. With this function you return a pointer to the first element of that array, but that pointer will immediately become invalid since it will point to something which no longer exist. Dereferencing it (which happens when you pass it to printf) will lead to undefined behavior.

第二个函数(function2)事情有点不同。这里的变量字符串函数内的局部变量。因此它将走出范围和函数返回后不复存在。这个函数返回一个指针指向第一个元素的数组,但指针将立即成为无效,因为它将指向的东西不再存在。非关联化它(当你通过printf)将导致未定义行为。

#3


7  

A very important thing to remember when coding in C or other stack based languages is that when a function returns, it (and all its local storage) is gone. This means that if you want someone else to be able to see the results of your methods hard work, you have to put it somewhere that will still exist after your method has ceased to, and to do that means you need to get an understanding of where C stores stuff and how.

在使用C或其他基于堆栈的语言编写代码时,需要记住的一件非常重要的事情是,当一个函数返回时,它(以及它所有的本地存储)就消失了。这意味着,如果你想让别人看到你的方法努力工作的结果,你必须把它放在某个地方后,仍然会存在你的方法已经停止,这意味着你需要得到一个C的商店的东西和了解。

You probably already know how an array operates in C. It is just a memory address that is incremented by the size of the object and you probably also know that C does not do bounds checking so if you want to access the 11th element of a ten element array, no one is going to stop you, and as long as you don't try to write anything, no harm done. What you may not know is that C extends this idea to the way it uses functions and variables. A function is just a area of memory on a stack that is loaded on demand and the storage for its variables are just offsets from that location. Your function returned a pointer to a local variable, specifically, the address of a location on the stack that holds the 'H' of 'Hello World\n\0' but when then you called another function (the print method) that memory was reused by the print method to do what it needed. You can see this easily enough (DO NOT DO THIS IN PRODUCTION CODE!!!)

您可能已经知道如何在C,它只是一个数组操作所增加的内存地址对象的大小,你可能也知道C没有边界检查如果你想访问一百一十年11日元素元素数组,没有人会阻止你,只要你不试着写什么,没有人受到伤害。您可能不知道的是,C将这个概念扩展到它使用函数和变量的方式。函数只是堆栈上按需加载的内存区域,其变量的存储只是与该位置的偏移量。函数返回一个指向局部变量的指针,具体地说,是堆栈上保存“Hello World\n\0”的“H”位置的地址,但是当您调用另一个函数(打印方法)时,该内存被打印方法重用,以完成需要的工作。您可以很容易地看到这一点(不要在生产代码中这样做!!!)

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'!

#4


5  

I thought the return value of both of the functions would be undefined since they are returning data that is out of scope.

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

No. That's not the case.

不。情况并非如此。

In function function1 you are returning pointer to a string literal. Returning pointer to a string literal is fine because string literals have static storage duration. But that's not true with automatic local variable.

在函数function1中,您将返回指向字符串文字的指针。返回指向字符串文字的指针是可以的,因为字符串文字有静态的存储时间。但自动局部变量不是这样的。

In function function2 the array string is an automatic local variable and the statement

在函数function2中,数组字符串是一个自动的局部变量和语句

return string; 

returns a pointer to an automatic local variable. Once the function return, the the variable string will no longer exist. Dereferencing the returned pointer will cause undefined behavior.

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

#5


0  

I thought the return value of both of the functions would be undefined since they are returning data that is out of scope.

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

Both functions return a pointer. What matters is the scope of the referent.

两个函数都返回一个指针。重要的是所指对象的范围。

In function1, the referent is the string literal "Hello, World!", which has static storage duration. string is a local variable which points to that string, and conceptually, a copy of that pointer is returned (in practice, the compiler will avoid unnecessarily copying the value).

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

In function2, conceptually the referent is the local array string, which has been automatically sized (at compile time) to be big enough to hold the string literal (including a null terminator, of course), and been initialized with a copy of the string. The function would return a pointer to that array, except that the array has automatic storage duration and thus no longer exists after exiting the function (it is indeed "out of scope", in more familiar terminology). Since this is undefined behaviour, the compiler may in practice do all sorts of things.

在function2中,从概念上来说,引用是本地数组字符串,它已经被自动调整大小(在编译时),大到足以容纳字符串文字(当然包括空终止符),并通过字符串的副本进行初始化。函数将返回一个指向该数组的指针,但是该数组具有自动的存储时间,因此在退出函数后不再存在(用更熟悉的术语来说,它确实“超出了范围”)。由于这是未定义的行为,编译器实际上可以做各种事情。

Does that mean that all char* are static?

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

Again, you need to distinguish between the pointer and the referent. Pointers point at data; they don't themselves "contain" the data.

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

You have reached a point where you should properly study what arrays and pointers actually are in C - unfortunately, it's a bit of a mess. The best reference I can offer offhand is this, in Q&A format.

您已经到达了一个点,您应该正确地研究数组和指针实际上是在C中——不幸的是,这有点混乱。我能立即提供的最好的参考是这个,以问答的形式。

#6


0  

"Hello, World!" is a string literal, which has a static storage duration, so the problem is elsewhere. Your first function returns the value of string, which is fine. The second function however returns the address of a local variable (string is the same as &string[0]), resulting in undefined behavior. Your second printf statement could print nothing, or "Hello, World!", or something else entirely. On my machine, the program just gets a segmentation fault.

“Hello, World!”是一个字符串文字,它有一个静态的存储时间,所以问题在其他地方。第一个函数返回字符串的值,这没问题。第二个函数返回本地变量的地址(字符串与&string[0]相同),导致未定义的行为。第二个printf语句不能打印任何内容,或者“Hello, World!”,或者别的什么。在我的机器上,程序只得到一个分割错误。

Always take a look at messages your compiler outputs. For your example, gcc gives:

总是查看编译器输出的消息。对于你的例子,gcc给出:

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

which is pretty much self-explanatory.

这是不言自明的。

#1


63  

the second function returns nothing

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

The string array in the second function:

第二个函数中的字符串数组:

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

has automatic storage duration. It does not exist after the control flow has returned from the function.

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

Whereas string in the first function:

而第一个函数中的字符串:

char* string = "Hello, World!";

points to a literal string, which has static storage duration. That implies that, the string still exists after returning back from the function. What you are returning from the function is a pointer to this literal string.

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

#2


25  

The first thing you need to learn about strings is that a string literal is really an array of read-only characters with a lifetime of the full program. That means they will never go out of scope, they will always exist throughout the execution of the program.

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

What the first function (function1) does is returning a pointer to the first element of such an array.

什么第一个函数function1()返回一个指向数组的第一个元素。

With the second function (function2) things are a little bit different. Here the variable string is a local variable within the function. As such it will go out of scope and cease to exist once the function returns. With this function you return a pointer to the first element of that array, but that pointer will immediately become invalid since it will point to something which no longer exist. Dereferencing it (which happens when you pass it to printf) will lead to undefined behavior.

第二个函数(function2)事情有点不同。这里的变量字符串函数内的局部变量。因此它将走出范围和函数返回后不复存在。这个函数返回一个指针指向第一个元素的数组,但指针将立即成为无效,因为它将指向的东西不再存在。非关联化它(当你通过printf)将导致未定义行为。

#3


7  

A very important thing to remember when coding in C or other stack based languages is that when a function returns, it (and all its local storage) is gone. This means that if you want someone else to be able to see the results of your methods hard work, you have to put it somewhere that will still exist after your method has ceased to, and to do that means you need to get an understanding of where C stores stuff and how.

在使用C或其他基于堆栈的语言编写代码时,需要记住的一件非常重要的事情是,当一个函数返回时,它(以及它所有的本地存储)就消失了。这意味着,如果你想让别人看到你的方法努力工作的结果,你必须把它放在某个地方后,仍然会存在你的方法已经停止,这意味着你需要得到一个C的商店的东西和了解。

You probably already know how an array operates in C. It is just a memory address that is incremented by the size of the object and you probably also know that C does not do bounds checking so if you want to access the 11th element of a ten element array, no one is going to stop you, and as long as you don't try to write anything, no harm done. What you may not know is that C extends this idea to the way it uses functions and variables. A function is just a area of memory on a stack that is loaded on demand and the storage for its variables are just offsets from that location. Your function returned a pointer to a local variable, specifically, the address of a location on the stack that holds the 'H' of 'Hello World\n\0' but when then you called another function (the print method) that memory was reused by the print method to do what it needed. You can see this easily enough (DO NOT DO THIS IN PRODUCTION CODE!!!)

您可能已经知道如何在C,它只是一个数组操作所增加的内存地址对象的大小,你可能也知道C没有边界检查如果你想访问一百一十年11日元素元素数组,没有人会阻止你,只要你不试着写什么,没有人受到伤害。您可能不知道的是,C将这个概念扩展到它使用函数和变量的方式。函数只是堆栈上按需加载的内存区域,其变量的存储只是与该位置的偏移量。函数返回一个指向局部变量的指针,具体地说,是堆栈上保存“Hello World\n\0”的“H”位置的地址,但是当您调用另一个函数(打印方法)时,该内存被打印方法重用,以完成需要的工作。您可以很容易地看到这一点(不要在生产代码中这样做!!!)

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'!

#4


5  

I thought the return value of both of the functions would be undefined since they are returning data that is out of scope.

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

No. That's not the case.

不。情况并非如此。

In function function1 you are returning pointer to a string literal. Returning pointer to a string literal is fine because string literals have static storage duration. But that's not true with automatic local variable.

在函数function1中,您将返回指向字符串文字的指针。返回指向字符串文字的指针是可以的,因为字符串文字有静态的存储时间。但自动局部变量不是这样的。

In function function2 the array string is an automatic local variable and the statement

在函数function2中,数组字符串是一个自动的局部变量和语句

return string; 

returns a pointer to an automatic local variable. Once the function return, the the variable string will no longer exist. Dereferencing the returned pointer will cause undefined behavior.

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

#5


0  

I thought the return value of both of the functions would be undefined since they are returning data that is out of scope.

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

Both functions return a pointer. What matters is the scope of the referent.

两个函数都返回一个指针。重要的是所指对象的范围。

In function1, the referent is the string literal "Hello, World!", which has static storage duration. string is a local variable which points to that string, and conceptually, a copy of that pointer is returned (in practice, the compiler will avoid unnecessarily copying the value).

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

In function2, conceptually the referent is the local array string, which has been automatically sized (at compile time) to be big enough to hold the string literal (including a null terminator, of course), and been initialized with a copy of the string. The function would return a pointer to that array, except that the array has automatic storage duration and thus no longer exists after exiting the function (it is indeed "out of scope", in more familiar terminology). Since this is undefined behaviour, the compiler may in practice do all sorts of things.

在function2中,从概念上来说,引用是本地数组字符串,它已经被自动调整大小(在编译时),大到足以容纳字符串文字(当然包括空终止符),并通过字符串的副本进行初始化。函数将返回一个指向该数组的指针,但是该数组具有自动的存储时间,因此在退出函数后不再存在(用更熟悉的术语来说,它确实“超出了范围”)。由于这是未定义的行为,编译器实际上可以做各种事情。

Does that mean that all char* are static?

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

Again, you need to distinguish between the pointer and the referent. Pointers point at data; they don't themselves "contain" the data.

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

You have reached a point where you should properly study what arrays and pointers actually are in C - unfortunately, it's a bit of a mess. The best reference I can offer offhand is this, in Q&A format.

您已经到达了一个点,您应该正确地研究数组和指针实际上是在C中——不幸的是,这有点混乱。我能立即提供的最好的参考是这个,以问答的形式。

#6


0  

"Hello, World!" is a string literal, which has a static storage duration, so the problem is elsewhere. Your first function returns the value of string, which is fine. The second function however returns the address of a local variable (string is the same as &string[0]), resulting in undefined behavior. Your second printf statement could print nothing, or "Hello, World!", or something else entirely. On my machine, the program just gets a segmentation fault.

“Hello, World!”是一个字符串文字,它有一个静态的存储时间,所以问题在其他地方。第一个函数返回字符串的值,这没问题。第二个函数返回本地变量的地址(字符串与&string[0]相同),导致未定义的行为。第二个printf语句不能打印任何内容,或者“Hello, World!”,或者别的什么。在我的机器上,程序只得到一个分割错误。

Always take a look at messages your compiler outputs. For your example, gcc gives:

总是查看编译器输出的消息。对于你的例子,gcc给出:

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

which is pretty much self-explanatory.

这是不言自明的。