[C Advanced] Dynamic Memory Management (1)

content

1. Why does dynamic memory allocation exist?

2. Introduction to dynamic memory functions

      2.1, malloc and free

      2.2、calloc

      2.3、realloc

3. Common dynamic memory errors

      3.1. Dereference operation on NULL pointer

      3.2. Cross-border access to dynamic development space

      3.3. Use free release for non-dynamically developed memory

      3.4. Use free to release part of a dynamically developed memory

      3.5. Release the same piece of dynamic memory multiple times

      3.6. Dynamically open up memory and forget to release (memory leak)


1. Why does dynamic memory allocation exist?

  • The memory development methods we have mastered are:
int val = 20;//在栈空间上开辟四个字节
char arr[1000] = {0};//在栈空间上开辟1000个字节的连续空间
  • However, the above-mentioned way of opening up space has two characteristics:
  1. The size of the space to open up is fixed.
  2. When an array is declared, the length of the array must be specified, and the memory it needs is allocated at compile time.

But the need for space is not limited to the above. Sometimes the size of the space we need can only be known when the program is running, and the way the array is compiled to open up space cannot be satisfied. For example, the size of 1000 bytes defined by the char type in the above code, if only 10 bytes are actually needed, the remaining 990 bytes will be wasted. .

At this time, you can only try to open up dynamic storage.

  • Review the space allocation opened up by dynamic memory:

2. Introduction to dynamic memory functions

2.1, malloc and free

  • malloc:

The C language provides a function for dynamic memory development:

void* malloc (size_t size);

This function requests a contiguous free space in memory and returns a pointer to this space.

  1. If the opening is successful, a pointer to the opened space is returned.
  2. If the development fails, a NULL pointer is returned, so the return value of malloc must be checked.
  3. The type of the return value is void*, so the malloc function does not know the type of the opened space, and the user himself
  4. to decide.
  5. If the parameter size is 0, the behavior of malloc is undefined by the standard and depends on the compiler.
  • Note: Use the malloc function to reference the header file #include<stdlib.h>
  • E.g:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……

	//释放
	return 0;
}
  • free:

The C language provides another function free, which is specially used for the release and recovery of dynamic memory. The function prototype is as follows:

void free (void* ptr);
  • The free function is used to release dynamically allocated memory.
  1. If the space pointed to by the parameter ptr is not dynamically allocated, the behavior of the free function is undefined.
  2. If the parameter ptr is a NULL pointer, the function does nothing.
  • Both malloc and free are declared in the stdlib.h header file.
  • For example, there are release and use links in the above code, and all the codes are perfected as follows:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

2.2、calloc

The C language also provides a function called calloc, which is also used for dynamic memory allocation. The prototype is as follows:

void* calloc (size_t num, size_t size);
  • num represents the number of elements, and size represents the size of each element.
  1. The function of the function is to open up a space for num elements of size size, and initialize each byte of the space to 0.
  2. The only difference from the function malloc is that calloc will initialize each byte of the requested space to all 0s before returning the address.
  • E.g:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

Compared with the mallo function, the malloc function is more efficient. The malloc function itself does not have the initialization function and directly returns the address.

2.3、realloc

The emergence of the realloc function makes dynamic memory management more flexible.

Sometimes we find that the space applied for in the past is too small, and sometimes we feel that the space applied for is too large. In order to use the
memory at a reasonable time, we must flexibly adjust the size of the memory. The realloc function can
adjust the size of dynamically allocated memory.

The function prototype is as follows:

void* realloc (void* ptr, size_t size);
  • ptr is the memory address to adjust
  • size is the new size after adjustment
  • The return value is the adjusted memory starting position.
  • On the basis of adjusting the size of the original memory space, this function will also move the data in the original memory to the new space.
  • There are two situations in which realloc adjusts the memory space:
  1. Case 1: There is enough space after the original space 
  2. Case 2: There is not enough space after the original space

  •  Case 1

In case 1, to expand the memory, add space directly after the original memory, and the data in the original space does not change.

  • Case 2

When it is case 2, when there is not enough space after the original 54 space, the expansion method is: find another continuous space of suitable size on the heap space to use. This function returns a new memory address.

Due to the above two situations, the use of the realloc function should be paid attention to. E.g:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//需要增容
	int* ptr = (int*)realloc(p, 80);
	if (NULL != ptr)
	{
		p = ptr;
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

3. Common dynamic memory errors

3.1. Dereference operation on NULL pointer

#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}
  • At this point we debug to see if p is empty:

  • The correct way of writing is as follows: should judge whether p is a null pointer
#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值

    // 判断:
 	if (p == NULL)
		return 0;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}

3.2. Cross-border access to dynamic development space

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//申请10个字符的空间:
	char* p = (char*)malloc(10 * sizeof(char));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//使用
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = 'a' + i; // i=10的时候越界访问
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}
  • The correct spelling is as follows:
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 'a' + i;
	}

3.3. Use free release for non-dynamically developed memory

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;
	return 0;
}

3.4. Use free to release part of a dynamically developed memory

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}

3.5. Release the same piece of dynamic memory multiple times

void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重复释放
}
  • A piece of space cannot be released again, but it can be released again by assigning it to a null pointer, as follows:
void test()
{
	int* p = (int*)malloc(100);
	free(p);
    p = NULL;
	free(p);//重复释放
}

3.6. Dynamically open up memory and forget to release (memory leak)

#include<stdio.h>
#include<stdlib.h>
void test()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 0;
	}
	//使用
	//……
	//忘记释放,就会出现内存泄露
}
int main()
{
	test();
	return 0;
}
  • If you forget to release, there will be a memory leak
  1. For functions with no return of void type, the release needs to be performed inside the function, otherwise the function will not be found after exiting the function.
  2. For functions with a return value, the return value can be released in the main function

In short, the application space will be released

Guess you like

Origin blog.csdn.net/bit_zyx/article/details/122737321