Advanced C language (explanation of common dynamic memory errors and analysis of interview questions)

content

foreword

1. Dynamic memory error

1. Dereference operation on NULL pointer

2. Out-of-bounds access to dynamically developed spaces

3. Use free to release non-dynamically developed space

4. Use free to release part of the dynamic memory

6. Forget to release the dynamically opened space (it is easy to cause memory leakage, which is more serious)

2. Analysis of dynamic memory error interview questions

1. The NULL pointer is passed as a temporary copy without taking the address.

2. Local variables and formal parameters exist on the stack

3. Remember to free the space opened by dynamic memory

4. Illegal access to memory

Summarize:


foreword

When we use the dynamic memory allocation function to write a program, there are often some undetectable and discovered errors in the process of writing, such as the dereference operation of the NULL pointer, the out-of-bounds access to the dynamically opened space, and the use of free to release. For non-dynamically opened space, use free to release part of the dynamic memory. For the same dynamically opened space, release it multiple times, and forget to release the dynamically opened space. Let's analyze one by one and analyze these common dynamic memory development problems.

1. Dynamic memory error

1. Dereference operation on NULL pointer

The code is as follows (example):

错误示例:
//动态内存开辟
int main()
{

	int* p = malloc(100000000000);
	//没有对mollac函数的返回值做判空处理
		int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	
	return 0;
}

正确示例:
//动态内存开辟
int main()
{

	int* p = malloc(100000000000);
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

2. Out-of-bounds access to dynamically developed spaces

The code is as follows (example):

错误示例:
//动态内存开辟
int main()
{

	int* p = (int*)malloc(10*sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
		//越界访问
	for (i = 0; i < 40; i++)//malloc函数只是开辟了十个整型的空间,这里却要访问四十个元素。
	{
		*(p + i) = 5;
	}
	for (i = 0; i < 40; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

正确示例:
//动态内存开辟
int main()
{

	int* p = (int*)malloc(10*sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
		
	for (i = 0; i < 10; i++)
		*(p + i) = 5;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

3. Use free to release non-dynamically developed space

The code is as follows (example):

//动态内存开辟
int main()
{
	int arr[10] = { 0 };//栈区
	int* p = arr;
	free(p);//使用free释放非动态开辟的空间
	p = NULL;
	return 0;
}

4. Use free to release part of the dynamic memory

The code is as follows (example):


//动态内存开辟
int main()
{
	int* p = malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*p++ = i;//1:p一直往后走之后没人知道起始空间的位置在哪,2:p释放的只是后面空间的一部分,前面的空间并没有得到释放。
	}
	free(p);
	p = NULL;
	return 0;
}

5. Release the space dynamically opened up by the same piece of dynamic memory multiple times

The code is as follows (example):

//动态内存开辟
int main()
{
	int* p = malloc(10 * sizeof(int));
	//使用
	//释放
	free(p);
	//再次释放
	free(p);//free要是传的是空指针什么事都不会发生。
	p = NULL;
	return 0;
}

6. Forget to release the dynamically opened space (it is easy to cause memory leakage, which is more serious)

The code is as follows (example):

void test()
{
	int* p = malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
	//使用
	//忘记释放
}

//动态内存开辟
int main()
{
	test();
	return 0;
}

2. Analysis of dynamic memory error interview questions

1. The NULL pointer is passed as a temporary copy without taking the address.

例题分析:

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

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

Program running result:

If the copy is unsuccessful, the program hangs directly.

Cause Analysis:

str传给GetMemory函数的时候是值传递,所以GetMemory函数的形参p是str的一份临时拷贝。
在GetMemory函数内部动态申请空间的地址,存放在P中,不会影响外面str,所以当GetMemory函数返回
之后,str任然是NULL指针,所以strcpy会失败。
当GetMemory函数返回之后,形参p销毁,使得动态开辟的100个字节存在内存泄漏。

 Correct code:

第一种改法:

char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}
void test(void)
{
	char* str = NULL;
	str = GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

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


第二种改法:

char* GetMemory(char** p)
{
	*p = (char*)malloc(100);
}
void test(void)
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

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

2. Local variables and formal parameters exist on the stack

The code is as follows (example):

例题分析:

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

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

Program running result:

The printing is unsuccessful, all random values ​​are printed

Cause Analysis:

GetMemory函数内部创建的数组是在栈区上创建的
出了函数,p的数组的空间就还给了操作系统
返回的地址是没有实际意义的,如果通过返回的地址,去访问内存就是非法访问内存。

 Correct code:

char* GetMemory(void)
{
	static char p[] = "hello world";
	return p;
}
void test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

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

3. Remember to free the space opened by dynamic memory

The code is as follows (example)

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}
int main()
{
	test();
	return 0;
}

Error analysis:

申请的动态内存空间使用完之后没有及时free释放掉。

Correct code:

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
	str = NULL;
}
int main()
{
	test();
	return 0;
}

4. Illegal access to memory

The code is as follows (example)

void test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
int main()
{
	test();
	return 0;
}

Error analysis:

申请的空间已经free释放还给操作系统了,及时str还记得这块空间的起始地址,但是也不能访问,属于非法访问内存空间。
free完之后要及时把str置成NULL指针。

Correct code:

void test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
int main()
{
	test();
	return 0;
}

Summarize:

The above briefly introduces several common problems in dynamic memory development, and also analyzes the mistakes in several interview questions in previous years, so that we can deepen our understanding of this chapter, and we can effectively avoid these when we use it ourselves. question. I believe everyone has learned it. If there are any problems with the above articles, you are welcome to ask questions. I will learn and correct them humbly. The most important thing is to make progress together, grow together, and learn programming well.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324194320&siteId=291194637