Dynamic memory allocation (stdlib.h must be included when using)

1. Dynamic memory function-malloc

void malloc(size_t size);

The malloc function applies for a continuous available space in memory and returns a pointer to this space.

① If the space is successfully opened, a pointer to the opened space will be returned.

② If the space opening fails, a NULL pointer will be returned, so the return value of malloc must be checked.

③The type of return value is void*, so the malloc function does not know the type of data to open up space for. The user decides when using it.

④If size is 0, the behavior of the malloc function is undefined by the standard and depends on the compiler.

The memory space requested by malloc is returned to the operating system when the program exits. When the program does not exit, the dynamic space applied for will not be actively released, so the free function to release the space is needed.

2. Release dynamic memory function-free

void free (void* ptr);

①If the space specified by the parameter ptr is not dynamically opened, then the behavior of the free function is undefined.

int main()
{
int a = 10;
int* p = & amp;a;
free(p);//error
return 0;

}

②If the parameter ptr is NULL, the function does nothing.

Examples of using malloc and free functions

#include<stdio.h>
#include<stdlib.h>//The use of dynamic memory functions must include the header file
int main()
{
int num = 0;
scanf("%d", & amp;num);
int* ptr = NULL;
ptr = (int*)malloc(num * sizeof(int));//Open up num spaces of type int
if (NULL == ptr)//Determine whether the dynamic memory allocation is successful, and print the error reason if it is unsuccessful.
{
perror("malloc");
return 1;//If development fails, return 1 to end the program, which is different from returning 0 below.
}
int i = 0;
for (i = 0; i < num; i + + )
{
printf("%d\\
", *(ptr + i));//After the malloc function opens up the space, it directly returns the pointer to the space and does not initialize the content of the space, so the printed value is a random value
}
for (i = 0; i < num; i + + )
{
*(ptr + i) = i;//assignment
printf("%d ", *(ptr + i));//print
}
free(ptr);//Release space
ptr = NULL;//Set ptr as a null pointer, otherwise ptr will become a wild pointer
return 0;
}

3. Dynamic memory function-calloc

void * calloc(size_t num, size_t size);

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

example:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)calloc(10, sizeof(int));
if (NULL == ptr)
{
perror("calloc");
return 1;
}
free(ptr);
ptr = NULL;
return 0;
}

4. Dynamic memory adjustment function-realloc

The realloc function is used to adjust the size of dynamically allocated space.

void * realloc(void * ptr, size_t size);

①ptr is the address of the memory to be adjusted

②size is the adjusted memory size

③The return value is the starting address of the adjusted memory

④The realloc function not only adjusts the original memory size, but also moves the data stored in the original memory to the newly opened memory.

⑤There are two situations when the realloc function adjusts the memory size.

●Case 1: There is enough unused space behind the original space that can be used to expand memory

example 1:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40); //First open up 40 bytes of space
if (NULL == ptr)
{
perror("malloc");
return 1;
}
printf("%p\\
", ptr); prints the starting address of dynamic memory space
int* p = NULL;
p = realloc(ptr, 60);//To adjust the memory, you need to use a new pointer to receive it first. You cannot use ptr to receive it, because if you use ptr to receive it, the memory adjustment fails and a NULL pointer is returned. Ptr cannot point to the originally opened space, causing memory problems. leakage
if (NULL == p)
{
perror("realloc");
return 1;
}
ptr = p;
printf("%p\\
", ptr);

return 0;
}

Original space The address is the same as the address of the newly opened space

●Case 2: There is not enough space behind the original space to expand the memory

The operations performed by the realloc function include:

1. Create a new space of suitable size

2. Copy the data from the old space to the new space

3. Release old space

4. Return the starting address of the new space

example 1:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
if (NULL == ptr)
{
perror("malloc");
return 1;
}
printf("%p\\
", ptr);
int* p = NULL;
p = realloc(ptr, 800);//The adjusted memory is too large and there are not enough addresses behind the original space. Therefore, realloc reopens the space and returns a new address pointing to the space.
if (NULL == p)
{
perror("realloc");
return 1;
}
ptr = p;
printf("%p\\
", ptr);
free(ptr);
ptr = NULL;
return 0;
}

Original space The address is different from the new space address

Example 2:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
if (NULL == ptr)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i + + )
{
*(ptr + i) = i;
}
int* p = NULL;
p = realloc(ptr, 80);
if (NULL == p)
{
perror("realloc");
return 1;
}
ptr = p;
for (i = 0; i < 20; i + + )
{
printf("%d\\
", *(ptr + i));
}
free(ptr);
ptr = NULL;
return 0;
}

New development The extra space will not be initialized.

Example 3: Reduce dynamic memory

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);//Apply for 10 integer-sized spaces
if (NULL == ptr)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i < 10; i + + )
{
*(ptr + i) = i;
}
int* p = NULL;
p = realloc(ptr, 20);//Adjust to 5 integer-sized spaces
if (NULL == p)
{
perror("realloc");
return 1;
}
ptr = p;
for (i = 0; i < 10; i + + )//still accessed 10 integers, out-of-bounds access
{
printf("%d\\
", *(ptr + i));
}
free(ptr);
ptr = NULL;
return 0;
}

Reduce memory Afterwards, the unnecessary space behind the original memory will be released and used by other programs.

5. Common dynamic memory errors

5.1 Dereference operation of NULL pointer

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
*ptr = 20;//Error, if the memory allocation fails, NULL should be dereferenced and ptr should be judged.
free(ptr);
ptr = NULL;
return 0;
}

5.2 Out-of-bounds access to dynamically opened space

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
if (NULL == ptr)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i <= 10; i + + )
{
*(ptr + i) = i;//When i = 10, it causes out-of-bounds access and program error
}
free(ptr);
ptr = NULL;
return 0;
}

5.3 Release of non-dynamically allocated memory

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

5.4 Use the free function to release a part of dynamically allocated memory

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
if (NULL == ptr)
{
perror("malloc");
return 1;
}
int i = 0;
for (i = 0; i <= 10; i + + )
{
*ptr + + = i;// + + operation makes ptr no longer point to the starting position of dynamically allocated memory
}
free(ptr);//An error will occur when releasing
ptr = NULL;
return 0;
}

5.5 Multiple releases of the same dynamic memory

#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(40);
free(ptr);
free(ptr);//repeated release, error
ptr = NULL;
return 0;
}

5.6 Dynamically allocated memory and forgetting to release it (memory leak)

The space applied for by dynamic memory will not be automatically destroyed when it goes out of scope. It can only be released by ① free function and ② automatically returned to the system when the program exits.

#include<stdio.h>
#include<stdlib.h>
void test()
{
int* p = (int*)malloc(40);
if (NULL == p)
{
perror("maollc");
return;
}
*p = 20; //Forgot to release memory after use
}
int main()
{
test();//After the test function, the local pointer variable p is destroyed, and the location of dynamically allocated memory cannot be found, causing a memory leak.
             The 40 bytes requested by malloc can no longer be used until the program exits
return 0;
}

6. Analysis of classic written test questions

6.1 Passing by value and address

void GetMemory(char *p)
{
 p = (char *)malloc(100);//The function parameter is a temporary copy of the actual parameter. The address of the dynamic memory saved by p will not be returned to str.
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);//Passing value does not change the actual parameters
 strcpy(str, "hello world");//Dereference of null pointer
 printf(str);//Dynamic memory is not released
}

Correct way to write:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);//Pass the address of str, str stores the starting address of dynamic memory
strcpy(str, "hello world");
printf(str);
free(str);//Release memory
str = NULL;
}
int main()
{
Test();
return 0;
}

6.2 Problem with returning stack space address

char *GetMemory(void)
{
 char p[] = "hello world";
 return p;//After exiting the GetMemory function, the array holding the helloworld string is destroyed and returned to the operating system.
}
void Test(void)
{
 char *str = NULL;
 str = GetMemory();//The space pointed by str has been returned to the operating system, and str becomes a wild pointer
 printf(str);//Dereference of wild pointer, illegal access
}

6.3 Forgetting to release memory

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

Correct way to write:

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

6.4 Set the pointer to empty after releasing the space

void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, "hello");
 free(str);//After releasing the memory, set the pointer to empty in time
 if(str != NULL)//The pointer is not set to null, the judgment is true, and the statement is executed
 {
 strcpy(str, "world");
 printf(str);
 }
}

Correct way to write:

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

7. Flexible array

In C99, the last element of a structure is allowed to be an array of unknown size. This array is called the [flexible array] member of the structure.

7.1 Definition of flexible array

#include<stdio.h>
typedef struct st_type
{
int i;
int a[0];//Flexible array members
}type_a;
typedef struct st_type1
{
int i;
int a[];//Flexible array members
}type_b;
int main()
{
printf("%d\\
", sizeof(type_a));//4, the size of the structure does not include the size of the flexible array
printf("%d\\
", sizeof(type_b));//4
return 0;
}

7.2 Characteristics of flexible arrays

1. The flexible array in the structure must be preceded by at least one other member

2. The size of the structure returned by sizeof does not include the memory of the flexible array.

3. The structure containing the flexible array uses 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.

7.3 Use of flexible arrays

typedef struct st_type1
{
int i;
int a[];
}type_a;
int main()
{
int i = 0;
type_a* p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
                        //Flexible array a has obtained 100 integer-sized spaces
p->i = 100;
for (i = 0; i < 100; i + + )
{
p->a[i] = i;
}
free(p);
p = NULL;
return 0;
}

Finished, scatter flowers!