Memory allocator - dynamic memory

Posted by notonurnelly on Tue, 21 Sep 2021 21:22:38 +0200

Dynamic memory management

Why is there dynamic memory allocation

What kind of memory development method have we mastered so far

//Create a variable
int val = 20;    //Local variables open up 4 bytes in stack space
int g_val = 10;  //The global variable opens up 4 bytes in the static area
//Create an array
char arr[10] = {0}; //The local area opens up 10 bytes of continuous space in the stack space
char g_arr[5] = {0};//The global area opens up a continuous space of 5 bytes in the static area space

However, the above-mentioned way of opening up space has two characteristics:

  1. The size of the space is fixed.
  2. When declaring an array, you must specify the length of the array, and the memory it needs will be allocated at compile time.
    But the demand for space is not just the above situation. Sometimes the size of the space we need can only be known when the program is running, and the way of opening up space during array compilation can not be satisfied. At this time, you can only try dynamic memory development.

c99 supports variable length arrays, but now many compilers do not support c99, even vs, so there is the concept of dynamic memory

Introduction to dynamic memory functions

malloc request space and free space

c language provides a function of dynamic memory development

void* malloc(size_t size);

This function requests a continuously available space from memory and returns a pointer to this space.

1. If the development is successful, a pointer to the developed space will be returned.

2. If the development fails, a NULL pointer will be returned. Therefore, 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 open space, which is determined by the user when using it*

4. If the parameter size is 0, the behavior of malloc is not defined in the standard, which depends on the compiler.

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

int main()
{
	//Request 10 shaping spaces from memory
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		//Print out the failed information
		printf("%s",strerror(errno));
	}
	else
	{
		//Normal use space
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;//Looking for element with index i
		}
		for (i = 0; i < 10; i++)//Then print out each element
		{
			printf("%d ", *(p + i));
		}
	}
	return 0;
}

Can we look at the failure of the development

We can use INT_MAX (he is the biggest), a super big number

Borrow and return free to free memory

The free function is used to free dynamic memory.
1. If the space pointed to by the parameter ptr is not dynamically opened up, the behavior of the free function is undefined.
2. If the parameter ptr is a NULL pointer, the function does nothing.

be careful

malloc and free are used in pairs. Who opens up and who releases

calloc request memory

Open up an array in memory and change the elements to zero

The function is to open up a space for num size elements, and initialize each byte of the space to 0.

The only difference between calloc and malloc is that calloc initializes each byte of the requested space to all zeros before returning the address

realloc resizes dynamic memory

Of course, we can apply for space, but will we encounter insufficient space, want to add some, and want to remove some when it is large

Precautions for using realloc

1. If there is enough memory space to append after the space pointed to by p, append directly and then return to p

2. If there is not enough memory space to add after the space pointed to by p, the realloc function will find a new memory area, open up a space to meet the needs, copy the data in the original memory back, release the old memory space, and finally return the newly opened memory space address

3. But there is also a big problem, that is, developing INT_MAX, use the new variable ptr to receive the return value of realloc

Of course, realloc can also directly open up space

Common dynamic memory errors

1. Dereference of NULL pointer

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

int main()
{
	int* p = (int*)malloc(40);//Without success, there will be big problems
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;
	return 0;
}

Therefore, in order to prevent the failure to open up dynamic memory, we need to make a judgment

2. Cross border visits to dynamic open spaces

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

int main()
{
	int* p = (int*)malloc(5*sizeof(int));
	if (p == NULL)//Here I do judge whether the development has been successful
	{
		printf("%s", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)//But I access 10 integer spaces here
		{
			*(p + i) = i;
		}
	}	
	free(p);
	p = NULL;
	return 0;
}

3. Use free to release non dynamic memory

int main()
{
	int a = 0;
	int* p = &a;
	*p = 20;
	free(p);
	p = NULL;
	return 0;
}

4. Use free to release part of a dynamic memory

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return 0;//If it is a null pointer, it will return directly and quit
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p++ = i;//This + + is where the bug is
	}
	//Recycle space
	free(p);
	p = NULL;
	return 0;
}

As long as p is not the first address pointing to the requested space, it is wrong everywhere else

5. Release the same dynamic memory multiple times

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

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return 0;
	}
	//use
	//release
	free(p);
	//...
	free(p);
	return 0;
}

6. Dynamic memory forgetting to release (memory leakage)

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

int main()
{
	while (1)
	{
		malloc(100);
	}
	return 0;
}

Several interview questions

Topic 1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str,"hello world");
	printf(str);//This is similar to printf("%s",str); It's the same
}
int main()
{
	Test();
	return 0;
}

Ask what the result will be when you run the Test function

Correct modification

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

void GetMemory(char* *p)
{
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str,"hello world");	
	printf(str);//This is similar to printf("%s",str); It's the same
	free(str);//Release after use
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

Topic 2

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

What will be the result of running the Test function

Output random value

Correct modification

Since p has been destroyed, we can let it not destroy it and prolong its life cycle with static

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;
}

Topic 3

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

This question is basically the same as the first question, but this question only has the error of memory leakage

Correct modification

#include<stdio.h>
#include<stdlib.h>
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);//Release after use to prevent memory leakage
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

Topic 4

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

Print out the results with very big problems

Correct modification

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

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);//What is examined here is that free does not make str NULL after it is released, so the following if judgment has no effect. If it makes it work, let str be NULL
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

The real purpose of this question is to let you print nothing

Memory development of C/C + + programs

Several areas of C/C + + program memory allocation:

  1. Stack: when executing a function, the storage units of local variables in the function can be created on the stack. These storage units are automatically released at the end of function execution. Stack memory allocation is built into the instruction set of the processor, which is very efficient, but the allocated memory capacity is limited. The stack area mainly stores the local variables, function parameters, return data, return address, etc. allocated for running the function.
  2. heap: it is generally allocated and released by the programmer. If the programmer does not release it, it may be recycled by the OS at the end of the program. The allocation method is similar to a linked list.
  3. The data segment (static area) stores global variables and static data. Released by the system at the end of the program.
  4. Code snippet: the binary code that holds the function body (class member function and global function).

Topics: C C++