C Language Anatomy Lesson Do you really fully understand function return values?

Mondo Technology Updated on 2024-02-05

Functions are the basic unit of language programming, and every meaningful function must produce input and output behavior. The topic of this article is not to discuss functions, but to dissect in detail what are the characteristics of the return value of functions that we have overlooked.

The reason why I wrote this topic is because I chatted with several newly hired programmers in the company in the past two days, all of whom are college students who have just graduated this year, and they all say that the basic skills are solid, and the basic skills are solid, which means that at least the professional courses are still very good.

Then of course, we have to talk about language. I don't know if I don't talk, but I'm shocked when I talk about it. A few people, even each of them can tell the return value of the function. In their understanding, the function returns data through the return value, and the other is through the pointer to bring the data out. Let them elaborate on it again, and they will be at a loss.

I asked them what the input parameters were and what the output parameters were, and none of them knew. The reason is that there is no syntax... That means they definitely don't know what semantics is and what syntax is.

Therefore, I decided to analyze the "return value of the function" with you today, and this article should be used as a starting point.

Everyone knows the composition of a function: the function name, the return value type, the parameter list, and the function body. The function enters the parameter through the parameter list, returns the data with the return statement, or returns the data from the output parameter in the parameter list.

The parameters that pass in the data of the function body are called the input parameters, and the parameters that pass the data out of the function are called the output parameters. Let's start with the return value.

If the return value is the data itself, or a specific value, that is, the value type, then we all know that this data is actually a copy of the data in the body of the function.

When the function is executed, the function object is automatically destroyed because it is allocated on the stack, so the mission is completed, and the memory space used by the data in the function will be released and redistributed. Therefore, before being destroyed, a copy is made and returned to the caller for use. (I'll dissect the memory layout in detail in the next post, and the stack and heap will be pretty clear).

The returned value type can be single-value data, such as a character-based variable, an integer variable, or a real number variable.

char foo()

char c='a';

return c;

int bar()

int x = 3;

return x;

These two functions return two single-value types, character and integer, respectively. It can also be multi-valued data, such as structs. A struct can contain multiple member variables within it. For example:

Returns multiple values.

typedef struct ;

return many;

Note that the string is not a value type, but a "pointer type" described below. An array is also not a value type, an array is essentially a "const pointer" (not a constant pointer), such as an integer array

int array =;

It's actually something like this:

int * const array = (int)

The array here can no longer be assigned by other arrays, i.e. it cannot be as follows:

int other_array = ;

array = other_array;//error

If you want to know the details, there are articles about constant pointers and pointer constant in-depth analysis in the "Duan Yuhe Language" account. As you can see, arrays are also a "pointer type".

If the returned data is pointer type data, a copy of the pointer type data will still be passed to the caller before the function is destroyed at the end of the function execution.

Note that this is where most beginners fall into the pit repeatedly.

Again: at the end of the function execution, like the value type, a copy of the data to be returned will be generated and passed to the caller, but this data (or copy) is the pointer type, and its value is stored in the memory address where the real value type data is located (assuming the pointer is a first-level pointer), note that the value type variable pointed to by the pointer does not have a "copy", only the return data will generate a copy, and the return data is a pointer.

For example: char* foo();

return array;

int* pointer_multiple_value_2()

return ptr;

When the function is executed, the data will also be destroyed, which will cause an exception when the caller accesses the memory data where the address is located through the obtained address. The result is as follows (environment vs, c11):

Let's take another look at a seemingly normal situation:

typedef struct ;

return &many;

many* pointer_multiple_value_4()

return many;

The return values of these two functions are struct pointers, one points to a single struct variable, and the other points to an array of structs, and after the function is executed, they will be destroyed like the function, resulting in undefined behavior of the memory block pointed to by the returned struct pointer, and the program is at risk of crashing.

This ** seems to be running normally, but in fact, it is easy to make him collapse, so I won't expand it for the time being.

So, we just need to make this value type, when the function is destroyed, it is still alive and not destroyed together.

If it is a string constant, it is stored in the read-only region, and when the function is destroyed, it still exists and can continue to be accessed.

char* foo();

return many;

This function allocates the space of a struct variable and assigns a value with a composite literal. Below is a screenshot:

Note that in this ** screenshot, in the main function, before the program exits, I used the free function to release the many pointer in the function foo.

This step is very important, before the end of the program, be sure to free up the space on the heap through the free function, otherwise "memory leak" or "memory fragmentation", "wild pointers" and other terrible problems will pop up.

Up to now, we have only analyzed and dissected the data type of "return value", and have not combined it with the feature of parameter lists.

In the next article, we will conduct an in-depth analysis of the parameter list of functions, such as the characteristics of "input parameters", the characteristics of "output parameters", and how to define some parameters for both incoming and outgoing data.

Studying the list of parameters will make the functions we write more secure and reliable, and the number of days of coding for 5 minutes and bugs for 5 hours will be significantly reduced.

Duan Yu, February 1, 2024, written in Hefei. List of high-quality authors

Related Pages