C language dynamic memory allocation function

Why does dynamic memory allocation exist

Let's first review the two methods of opening up memory space that we have learned:

	int a = 0;//在栈区上开辟四个字节的空间
	char ch[10] = {
    
     0 };//在栈区上开辟十个字节的连续空间

This method of allocating space has two characteristics:
1. The space allocated is fixed;
2. When declaring an array, the length of the array must be specified, and memory space is allocated for it during program compilation.

However, these two methods are far from meeting the demand for space. Sometimes the size of the space we need to use needs to be known when the program is running. For example, in my last blog: In C language implementation of address book (static version) , the size of our address book is fixed.
insert image description here
The size of the address book is 100, that is, it can only save the information of 100 contacts at most, so what if we need to save 200 or more people when we use it? Then this program cannot meet our needs. To solve this problem, we have to学会使用C语言动态内存分配函数,对通讯录的大小进行动态分配。

Introduction to dynamic memory allocation functions

A header file is required to use the function: <stdlib.h>
C language provides three dynamic memory allocation functions: malloc, calloc, realloc. And it should be noted that these three functions all apply for space in the heap area, and the space allocated in the heap area will not automatically release memory like the space allocated in the stack area , so C language also provides a freefunction for manual release The memory space opened up by the heap area, so as not to happen 内存泄漏.

1. malloc

malloc - void* malloc (size_t size);
working principle:

  1. 堆区The malloc function will apply for a continuous space in the memory , and the space size is sizein bytes.
  2. If the memory is allocated successfully, the function returns the address of the starting position of the allocated space; otherwise, it returns NULLa pointer. So be sure to check the return value after using the malloc function.
  3. The pointer type returned by the malloc function is viod*, and we need to cast it ourselves.
  4. If sizethe size of the incoming parameter is 0, this behavior is defined by the C language standard and depends on the compiler.

Use Cases:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
	int num = 0;
	scanf("%d", &num);
	//int arr[num] = { 0 };error

	//使用动态内存分配
	int* ptr = NULL;
	ptr = (int*)malloc(num * sizeof(int));
	if (ptr != NULL)//检查函数的返回值是否正常
	{
    
    
		//使用空间
		for (int i = 0; i < num; i++)
		{
    
    
			*(ptr + i) = i;
		}
		for (int i = 0; i < num; i++)
		{
    
    
			printf("%d ", *(ptr + i));
		}
	}
	//释放内存空间并将ptr指针置空
	free(ptr);
	ptr = NULL;

	return 0;
}

Program running results:
insert image description here
It should be noted that after using the free function to release the space at the end, we also need to empty the ptr function, otherwise the ptr function will point to a space that no longer belongs to us, resulting in problems such as out-of-bounds access.

2. calloc

calloc - void* calloc (size_t num, size_t size);
working principle:

  1. The calloc function will open up num spaces of size bytes, and assign all bytes of the space to 0.
  2. The difference between the calloc function and the malloc function is that the calloc function will actively assign a value of 0 to the opened space.
    Use cases:
#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
	int num = 0;
	scanf("%d", &num);
	//int arr[num] = { 0 };error

	//使用动态内存分配
	int* ptr = NULL;
	ptr = (int*)calloc(num, sizeof(int));
	if (ptr != NULL)//检查函数的返回值是否正常
	{
    
    
		//使用空间
		for (int i = 0; i < num; i++)
		{
    
    
			printf("%d ", *(ptr + 1));
		}
		printf("\n");
		for (int i = 0; i < num; i++)
		{
    
    
			*(ptr + i) = i;
		}
		for (int i = 0; i < num; i++)
		{
    
    
			printf("%d ", *(ptr + i));
		}
	}
	//释放内存空间并将ptr指针置空
	free(ptr);
	ptr = NULL;

	return 0;
}

Program running results:
insert image description here
It can be seen that the active assignment is indeed 0. I personally think that the better point of the calloc function is that it is convenient for initialization.

3. realloc

realloc - void* realloc (void* ptr, size_t size);
working principle:

  1. ptr represents the first address of the space to be modified.
  2. size represents the modified memory space size
  3. The realloc function returns the modified address of the first element.
    Note: There are two situations in which the realloc function modifies the memory space.
    1. If the space behind the memory to be expanded is large enough, open up space directly behind the space.
    2. If there is no space behind the memory to be expanded If there is enough space, the function will find a suitable space to store the new space.
    Illustration:
    insert image description here

4. free

free ——void free (void* ptr);
working principle:

  1. free releases the memory space pointed to by ptr.
  2. If the space pointed to by the parameter ptr is not dynamically opened, the behavior of the free function is undefined.
  3. If the parameter ptr is a NULL pointer, the function does nothing.
  4. The free function is only responsible for releasing the memory space, and does not modify the ptr pointer, so after calling the free function, the ptr pointer should be set to NULL to avoid illegal access.

That is, we can get the code writing method to release the memory space:

free(ptr);
ptr=NULL;

Some error cases of dynamic memory allocation

1. Dereference operation on NULL pointer

void test()
{
    
    
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}

insert image description here

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

void test()
{
    
    
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
    
    
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
    
    
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}

It is wrong to access out of bounds whether it is in the stack area or the heap area. Here, the malloc function only applies for 40 bytes of space, which can store 10 integer-sized variables, and when i==10, it is actually the 11th element, which will cause out-of-bounds access.

3. Use free to release non-dynamically allocated memory

We have said this before, the space is not dynamically opened, the behavior of the free function is undefined.

void test()
{
    
    
int a = 10;
int *p = &a;
free(p);//ok?
}

program run error
insert image description here

4. Use free to release part of a dynamically allocated memory

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

The same reason is also a program error, and there is no definition of this behavior in vs2022
insert image description here

5. Multiple releases of the same dynamic memory

In fact, it is similar to 3, the code is as follows:

void test()
{
    
    
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}

insert image description here

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

void test()
{
    
    
int *p = (int *)malloc(100);
if(NULL != p)
{
    
    
*p = 20;
}
}
int main()
{
    
    
test();
while(1);
}

Forgetting to release the dynamically allocated space that is no longer used will cause memory leaks.
The dynamically allocated memory space will not be released automatically, and will only be released when the program ends. So if it is not released in time, the program will always eat memory.
So remember: the dynamically opened space must be released, and released correctly

Summarize

Learning to dynamically allocate memory makes us more flexible when writing programs. Through the above study. I think we can now solve the problem that the address book in the last blog has only a fixed size. I will give a tutorial in a later blog, that is, an address book with a dynamically allocated size, and file operations can be performed. Look forward to it!
insert image description here

Guess you like

Origin blog.csdn.net/m0_72482689/article/details/127138770