C language --- Segmentation fault caused by formal parameters

foreword

I browsed station B today, and accidentally saw an embedded interview question that claimed that 90% of people would be wrong. I took a look if I was interested. It took more than ten minutes to figure it out. It's just a little knowledge point, but I still want to share it.

topic

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getmemory(char *p)
{
    
    
	p = (char*)malloc(100);
}

void test(void)
{
    
    
	char *str = NULL;
	getmemory(str);
	strcpy(str,"hello world");
	printf("%s\n",str);
}

int main()
{
    
    
	test();
	return 0;
}

(1) Let's see, what's wrong with the above string of codes? In fact, it is a very simple knowledge point, but it is easy to get stuck.
(2) If you can't figure out the problem with this string of codes, just run it directly.
(3) Judging from the running results, a segment error is reported. Then we need to know the possible reasons for segment faults:
<1> Access to unallocated memory : When the program tries to access unallocated memory areas, such as using uninitialized pointers or pointers to access arrays out of bounds, it will cause segment faults .
<2> Accessing a null pointer : When a program tries to access a null pointer, that is, a pointer pointing to a null address, without performing an effective null pointer check, it will cause a segment fault.
<3> Memory out-of-bounds access : When the program tries to access a memory location beyond the bounds of the array, that is, it accesses memory outside the array, it will also cause a segment fault.
<4> Wild pointer : When the program uses the memory that has been released or the pointer that has expired, a wild pointer will be generated, which will lead to a segment fault.
<5> Memory alignment error : Some architectures require that access to memory addresses of specific data types must be performed according to a certain alignment. If the alignment requirement is violated, a segment fault will result.
<6> Stack overflow : When the recursive call level of the program is too deep or the stack space is exhausted due to the use of too many local variables, a segmentation fault may also be caused.
<7> Other abnormal conditions : such as accessing read-only memory, errors in signal handlers, etc. may also cause segment faults.

insert image description here

identify the problem

(1) After we know the possibility of segment faults, we start to locate the possible causes.
<1>Access unallocated memory, the program tries to access unallocated memory area: This is possible, because in the getmemory() function, the malloc function may not allocate an area.
<2>Accessing a null pointer: Because str is initially initialized as a null pointer, the malloc function in the getmemory() function may not return to str.
<3> Memory out-of-bounds access: malloc applies for 100 bytes of data, while "hello world" only has a total of 12 bytes of data (note that there is '\0' at the end of the string). So this possibility is relatively small.
<4> Wild pointer: Although the memory is applied for here, it is not released, so the possibility is relatively small.
<5> Memory alignment: This string of codes has no memory alignment content. So the possibility is also very small.
<6>Stack overflow: Only 100 bytes of data are applied here, and the possibility of overflow is relatively small.
<7> Access to read-only memory does not appear here, so the possibility is relatively small.
(2) In summary, it is possible that malloc did not allocate memory to cause a segment fault, or that malloc applied for memory, but did not pass the returned data to str.

Determine whether malloc successfully applied for memory

(1) We need to judge whether malloc successfully applied for memory, so I plan to put the strcpy() function in getmemory().
(2) It is found that it can run successfully, so the malloc memory application is successful.

insert image description here

Judging whether it is a problem of accessing a null pointer

(1) If str is a null pointer, a segment fault will occur, so I add a parameter to print the address stored in str after the getmemory() function.
(2) Judging from the running results, it is found that str is indeed a null pointer.

insert image description here

problem analysis

(1) Now we know that the problem is that str is a null pointer. So why is str a null pointer?
(2) This needs to involve the parameter passing process of the function. We all know that the parameter passed in the function is a formal parameter. The formal parameter variable allocates a memory unit only when it is called, and releases the allocated memory unit immediately when the call ends. Therefore, formal parameters are only valid inside the function.
(3) Then there is a problem, malloc has applied for a memory area, and the first address of this area is assumed to be 0x3fff. After returning to p, because p is a formal parameter, it is released after the function ends, and the value 0x3fff is not passed to str.
(4) The following is a diagram

insert image description here
insert image description here
insert image description here
insert image description here

how to change

(1) After knowing the working principle of the formal parameter, it is easy to change it. In the process of passing parameters, we can use secondary pointers. The diagram is as follows

insert image description here
insert image description here
insert image description here
insert image description here

(2) After changing to the secondary pointer, we also need to know that every time malloc applies for memory, we must remember to release the memory. So I also added a freememory() function.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getmemory(char **p)
{
    
    
	*p = (char*)malloc(100);
}

void freememory(char **p)
{
    
    
	free(*p);
	*p = NULL;
}

void test(void)
{
    
    
	char *str = NULL;
	getmemory(&str);
	strcpy(str,"hello world");
	printf("%s\n",str);
	freememory(&str);
}

int main()
{
    
    
	test();
	return 0;
}

Guess you like

Origin blog.csdn.net/qq_63922192/article/details/131145688