[C Advanced] Dynamic Memory Management (2)

content

1. Classic written test questions

      Question 1

      Question 2

      Question 3

      Question 4

2. Memory development of C/C++ programs

3. Flexible array

       3.1. Features of flexible arrays

       3.2, the use of flexible arrays

       3.3. Advantages of flexible arrays


1. Classic written test questions

Question 1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}
//请问运行Test 函数会有什么样的结果?

Running result: program crashes

  • main problem:

The str pointer variable puts a null pointer, and then calls the GetMemory function, which passes the str pointer variable itself, p is actually a temporary copy of str, the current p is NULL, and malloc is in the memory heap area at this time 100 bytes of space has been applied for, and the starting address is returned. Suppose it returns 0x0012ff80 and put it in p. p is a formal parameter. Once the GetMemory function is executed, p is destroyed. At this time, the 100-byte size The space address cannot be found. The change of p will not cause the change of str. At this time, str is still a null pointer. At this time, if you put hello world into str and take it, there will be a problem, and the memory will be accessed illegally.

  • Minor questions:
  1. Using malloc function does not determine whether it is a null pointer
  2. Not released after the end
  • Solution: pass the address
  • Law one:
void 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;
}
  • Law two:
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;
}

Question 2

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
//请问运行Test 函数会有什么样的结果?
  • result:

  • Parse:

First, a pointer variable str is created and assigned a null pointer, str receives the return value of GetMemory, the p array is placed hello world\0, and it is a space opened up on the stack, the array is only inside the GetMemory function Effective, it will be destroyed when the function is out. Even if the address is returned, but out of the function, the space of hello world\0 no longer exists. At this time, str is a wild pointer. To access the memory again is to access the memory illegally, so print random value

  • Solution:
  • Method 1: (static modification)
char* GetMemory(void)
{
	static char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
  • Law two:
char* GetMemory(void)
{
	char *p = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

Question 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);
}
//请问运行Test 函数会有什么样的结果?
  • result:

  • Parse:

Although the result outputs hello as expected, there is a problem with this code, that is, it is not released, which will cause memory leaks

  • Solution:
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;
}

Question 4

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
//请问运行Test 函数会有什么样的结果?
  • result:

  • Parse:

First, open up 100 bytes of space and put it in str, strcpy will copy hello\0 into str, and then free str to release the space pointed to by str, but free itself will not make str become a null pointer. Copy world to str, but the space pointed to by str has been freed and returned to the operating system before, and cannot be used again. If you copy world to str, you will access memory illegally.

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

2. Memory development of C/C++ programs

  •  Several areas of C/C++ program memory allocation:
  1. Stack area (stack): When the function is executed, the storage units of local variables in the function can be created on the stack, and these storage units are automatically released when the function execution ends. The stack memory allocation operation is built into the processor's instruction set, which is very efficient, but the allocated memory capacity is limited. The stack area mainly stores local variables, function parameters, return data, return addresses, etc. allocated by running functions.
  2. Heap area (heap): Generally allocated and released by the programmer. If the programmer does not release it, it may be reclaimed by the OS at the end of the program. The allocation method is similar to a linked list.
  3. The data segment (static area) (static) stores global variables and static data. Released by the system after the program ends.
  4. Code segment: The binary code that stores the function body (class member functions and global functions).
  • With this picture, we can better understand the example of the static keyword modifying local variables.

In fact, ordinary local variables are allocated space in the stack area. The characteristic of the stack area is that the variables created above are destroyed when they go out of scope. However, the variables modified by static are stored in the data segment (static area). The characteristic of the data segment is that the variables created above are not destroyed until the end of the program, so the life cycle becomes longer.

3. Flexible array

In C99, the last element in a structure is allowed to be an array of unknown size, which is called a "flexible array" member.

  • E.g:
typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
  • Some compilers will report an error that cannot be compiled and can be changed to:
typedef struct st_type
{
	int i;
	int a[];//柔性数组成员
}type_a;

3.1. Features of flexible arrays

  1. A flexible array member in a structure must be preceded by at least one other member.
  2. The size of this structure returned by sizeof does not include the memory of the flexible array.
  3. Structures containing flexible array members use the malloc() function to dynamically allocate memory, and the allocated memory should be larger than the size of the structure to accommodate the expected size of the flexible array.
  • E.g:
typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
int main()
{
	printf("%d\n", sizeof(type_a));//输出的是4
	return 0;
}

3.2, the use of flexible arrays

typedef struct st_type
{
	int i;
	int a[0];//柔性数组成员
}type_a;
//代码一:
int main()
{
	type_a* p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
	//业务处理
	p->i = 100;
	int i = 0;
	for (i = 0; i < 100; i++)
	{
		p->a[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

In this way, the flexible array member a is equivalent to obtaining a continuous space of 100 integer elements.

3.3. Advantages of flexible arrays

  • The above type_a structure can also be designed as:
typedef struct st_type
{
	int i;
	int* p_a;
}type_a;
//代码2
int main()
{
	type_a* p = (type_a*)malloc(sizeof(type_a));
	p->i = 100;
	p->p_a = (int*)malloc(p->i * sizeof(int));
	//业务处理
	int i = 0;
	for (i = 0; i < 100; i++)
	{
		p->p_a[i] = i;
	}
	//释放空间
	free(p->p_a);
	p->p_a = NULL;
	free(p);
	p = NULL;
	return 0;
}

The above code 1 and code 2 can accomplish the same function, but the implementation of method 1 flexible array has two advantages:

  • The first benefit is: easy memory release

If our code is in a function that is used by others, you do a second memory allocation in it and return the entire structure to the user. The user can free the structure by calling free, but the user doesn't know that the members of the structure also need to be free, so you can't expect the user to find out. Therefore, if we allocate the memory of the structure and the memory required by its members at one time, and return a structure pointer to the user, the user can release all the memory by doing a free.

  • The second benefit is: this is good for access speed.

Contiguous memory is beneficial for improving access speed and reducing memory fragmentation.

Guess you like

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