0. Preface
Why is there dynamic memory allocation?
int val = 20;//Open up four bytes in stack space char arr[10] = {0};//Open up 10 bytes of continuous space on the stack space Such static variables are hard to tune,Drought death,Waterlogging death
- The size of the space is fixed.
- When declaring an array, you must specify the length of the array, and the memory it needs will be allocated at compile time.
The space requested for dynamic memory allocation is on the heap
1. Dynamic memory function
malloc
void *malloc( size_t size ); malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small. malloc Returns a pointer to the allocated space void Pointer, if the available memory is insufficient, return NULL. To return a non void Type pointer, please type convert the return value. The storage space pointed to by the return value ensures proper alignment of objects of any type. If size Is 0,malloc An item of length 0 is allocated in the heap and a valid pointer to the item is returned. Always check malloc Even if the requested amount of memory is small
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { //Open up 10 integer spaces int* p = (int*)malloc(4000000000000000); if (NULL == p) { printf("%s\n", strerror(errno));//Not enough space } return 0; }
free
void free( void *memblock ); Previously allocated memory block to be freed If the space opened up is not released,Then others can't use it
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { //Open up 10 integer spaces int* p = (int*)malloc(40);//malloc returns void* if (NULL == p) { printf("%s\n", strerror(errno));//Not enough space } //use if (p)//You need to check the validity of the pointer or add return to the if above; { for (size_t i = 0; i < 10; i++) { *(p + i) = i; } for (size_t i = 0; i < 10; i++) { printf("%d ", p[i]);//0 1 2 3 4 5 6 7 8 9 } } //release free(p);//After the space is released, P saves the same address, so p becomes a wild pointer p = NULL;//Set p to NULL after all spaces pointed to by P are released return 0; }
calloc
void *calloc( size_t num, size_t size ); Allocates an array in memory with elements initialized to 0.
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { //Open up 10 integer spaces int* p = (int*)calloc(10,sizeof(int));//calloc also returns void* if (NULL == p) { printf("%s\n", strerror(errno));//Not enough space } //use if (p) { /*for (size_t i = 0; i < 10; i++) { *(p + i) = i; }*/ for (size_t i = 0; i < 10; i++) { printf("%d ", p[i]);//0 0 0 0 0 0 0 0 0 0 } } //release free(p);//After the space is released, P saves the same address, so p becomes a wild pointer p = NULL;//Set p to NULL after all spaces pointed to by P are released return 0; }
realloc
void* realloc (void* ptr, size_t size); Reallocate memory blocks. 1.Can open up space 2.You can also adjust the space Pointer to a memory block previously allocated with malloc, calloc or realloc.Alternatively, this can be a null pointer, in which case a new block is allocated (as if malloc was called). realloc If it is found that the original space is not expanded enough,Will find a new space to open up,And take down the value of the original space,And free up the original space If realloc Adjustment failed,Return null pointer Never write that:p = (int*)realloc(p, 80); This may cause the original memory block to leak Just write it like this int* ptr = (int*)realloc(p, 80); if (NULL != ptr) { p = ptr; }
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { //Open up 10 integer spaces int* p = (int*)calloc(10, sizeof(int));//calloc also returns void* if (NULL == p) { printf("%s\n", strerror(errno));//Not enough space } //use if (p) { for (size_t i = 0; i < 10; i++) { printf("%d ", p[i]);//0 0 0 0 0 0 0 0 0 0 } } //Insufficient space, need to expand capacity int* ptr = (int*)realloc(p, 80); if (NULL != ptr) { p = ptr; } //release free(p);//After the space is released, P saves the same address, so p becomes a wild pointer p = NULL;//Set p to NULL after all spaces pointed to by P are released return 0; }
r //Open up 10 integer spaces int* p = (int*)realloc(NULL, 40);//If realloc passes NULL, it is equivalent to malloc if (NULL == p) { printf("%s\n", strerror(errno));//Not enough space }
2. Common errors
Dereference to NULL pointer
#include<stdio.h> #include<limits.h> #include<stdlib.h> int main() { int* p = (int*)malloc(INT_MAX);//#define INT_MAX 2147483647 int i = 0; for ( i = 0; i < 10; i++) { *(p + i) = i; } return 0; }
#include<stdio.h> #include<limits.h> #include<stdlib.h> #include<assert.h> int main() { int* p = (int*)malloc(INT_MAX);//#define INT_MAX 2147483647 assert(p);//Assertion failed: p, if the development fails, a null pointer is returned if (p) { int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i; } } return 0; }
Or modify it like this: if (p == NULL) { printf("%s\n", strerror(errno)); return 0; } //use int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i; }
Cross border access to dynamic open space
#include<errno.h> #include<string.h> #include<stdio.h> #include<stdlib.h> int main() { char* p = (char*)malloc(10 * sizeof(char)); if (p == NULL) { printf("%s\n", strerror(errno)); return 0; } //use for (size_t i = 0; i <= 10; i++) { *(p + i) = 'a' + 1;//e } //release free(p); p = NULL; return 0; }
The free function is used for non dynamic memory
void test() { int a = 10; int *p = &a; free(p);//err }
Use free to release a part of dynamic memory
void test() { int *p = (int *)malloc(100); p++; free(p);//p no longer points to the starting position of dynamic memory. If p cannot find the starting position, there is a risk of memory leakage //err }
Multiple releases of the same dynamic memory
void test() { int *p = (int *)malloc(100); free(p); free(p);//Repeated release procedure will jam }
void test() { int *p = (int *)malloc(100); free(p); p = NULL; free(p);//It's OK to release the free null pointer repeatedly, but it's better not to repeat free }
Dynamic memory forgetting to release (memory leak)
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } //If you forget to release, there will be a memory leak. Others can't use that space } int main() { test(); while(1); } //Who applies for release
3. Written test questions
1.
void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str);//Value passing call strcpy(str, "hello world");//str is still a null pointer. At this time, it is illegal to access memory, and the program will crash printf(str);//It's OK to write like this } int main() { Test(); return 0; } //Running result: the program crashed and there was nothing
char* p = "hello world";//Actually, it's the first address printf("hello world"); printf(p);//It's the first address. It can be written like this
Modify: address calling is enough void GetMemory(char** p) { *p = (char*)malloc(100); } void Test(void) { char* str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf(str);//It's OK to write like this //release free(str); str = NULL; } int main() { Test();//hello world return 0; }
char* GetMemory(char* p) { p = (char*)malloc(100);//Dynamically requested space will not be destroyed return p; } void Test(void) { char* str = NULL; str = GetMemory(str); strcpy(str, "hello world"); printf(str);//It's OK to write like this //release free(str); str = NULL; } int main() { Test();//hello world return 0; } //No address, return pointer is OK "be careful: p Although it will be destroyed, it will be destroyed before p Put it in the register" The space requested by the dynamic memory function is in the heap area and will not be destroyed like local variables
2.
//Return stack space address problem //Note that it is different from the return variable itself char *GetMemory(void) { char p[] = "hello world";//Local variables are destroyed return p; //At the end of the function, p will be destroyed. p is the address. The address can be returned, but the space pointed to by the address has been destroyed and is useless } void Test(void) { char *str = NULL; str = GetMemory(); printf(str);//Random value, perm } int main() { Test();// return 0; }
int test() { int a = 10; return a;//The return variable itself is OK, because when returning, the value of a will be put into the register, and then the value of the register will be returned to m } int main() { int m = test(); printf("%d\n",m); return 0; }
int* test() { int a = 10; return &a; } int main() { int* p = test(); printf("%d\n", *p);//Printing out 10 is a fluke, random value return 0; }
int* test() { int a = 10; return &a; } int main() { int* p = test(); printf("hehe\n");//At this time, the space applied for this sentence printf will cover the original space of a printf("%d\n", *p);//Another random value is printed out return 0; }
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); //Forget free //The following should be added: free(str); str = NULL; }
4.
void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); if(str != NULL) { strcpy(str, "world");//The space pointed to by str has been released and cannot be used again, resulting in illegal access to memory //Therefore, str should be set to NULL in time printf(str); } }
4. Memory development of C / C + +
4. Memory development of C / C + + program
The constant string is placed in the code snippet
From kernel space to code segment, it is from high address to low address
-
Stack: when executing a function, the storage units of local variables in the function can be created on the stack, and these storage units are automatically released at the end of function execution. The stack memory allocation operation 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.
-
heap: it is usually 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.
-
The data segment (static area) stores global variables and static data. Released by the system at the end of the program.
-
Code snippet: the binary code that stores the function body (class member function and global function).
5. Flexible array
In C99, the last element in the structure is allowed to be an array of unknown size, which is called "flexible array" member.
//Two ways to write flexible arrays struct S1 { int n; int arr[0];//Size not specified }; struct S2 { int n; int arr[];//Size not specified }; int main() { printf("%d\n", sizeof(struct S1));//4 printf("%d\n", sizeof(struct S2));//4 return 0; }
characteristic
- A flexible array member in a structure must be preceded by at least one other member.
- The size of this structure returned by sizeof does not include the memory of the flexible array.
- A structure containing flexible array members, and the allocated memory should be greater than the size of the structure to accommodate the expected size of the flexible array.
struct S2 { int n; int arr[];//Size not specified }; int main() { printf("%d\n", sizeof(struct S1));//4 printf("%d\n", sizeof(struct S2));//4 struct S2* ps = (struct S2*)malloc(sizeof(struct S2) + 40); ps->n = 100; for (size_t i = 0; i < 10; i++) { ps->arr[i] = i; } //... //increase capacity struct S2* ptr = (struct S2*)realloc(ps, sizeof(struct S2) + 80); if (ptr == NULL) { return 0; } else { ps = ptr; } //Continue to use //Only one release is required free(ps); ps = NULL; return 0; }
contrast:
struct S { int n; int* arr; }; int main() { struct S* ps = (struct S*)malloc(sizeof(struct S)); ps->n = 100; ps->arr = (int*)malloc(40);//It's all on the pile //use //increase capacity //2 releases free(ps->arr); ps->arr = NULL; free(ps); ps = NULL; return 0; }
What if there are n more variables in front of the flexible array? Will their address space be continuous? Not necessarily, so flexible arrays are still necessary
Moreover, the number of flexible array development and release is less, and it is not easy to make mistakes
The more development times, the more memory fragments will be generated
And continuous memory is conducive to improve access speed
6. Address book
test.c
#define _CRT_SECURE_NO_WARNINGS 1 //1. Store information of 1000 people //2. Relevant information of the person, name, age, telephone number, address and gender //3. Addition, deletion, query and modification //4. Sorting #include"contact.h" enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, SHOW, CLS }; void menu() { printf("***************************************\n"); printf("******** 1.add 2.del *****\n"); printf("******** 3.search 4.modify *****\n"); printf("******** 5.sort 6.show *****\n"); printf("******** 7.cls 0.exit *****\n"); printf("***************************************\n"); } int main() { int input = 0; static Contact con;//mail list //Initialize address book InitContact(&con); do { menu(); printf("Please select:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL: DeleteContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: ModifyContact(&con); break; case SORT: SortContact(&con); break; case SHOW: ShowContact(&con); break; case CLS: ClsContact(); break; case EXIT: //Recycle address book DestroyContact(&con); break; printf("Exit address book\n"); default: printf("Selection error\n"); break; } }while(input); return 0; }
contact.h
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<memory.h> #include<assert.h> #include<string.h> #include<stdlib.h> #include<errno.h> #include<Windows.h> #define MAX 1000 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 30 #define TELE_MAX 12 #define DEFAULT_SZ 3 / / the number of people stored by default typedef struct Peoinfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char addr[ADDR_MAX]; char tele[TELE_MAX]; }Peoinfo; //Structure of address book typedef struct Contact { //Peoinfo data[MAX]; Peoinfo* data; int sz;//Number of valid messages in the address book int capacity;//Record the maximum capacity of the current address book }Contact; //Initialize address book void InitContact(Contact* pc); //Destroy address book void DestroyContact(Contact* pc); //Add contact information void AddContact(Contact* pc); //Show contacts void ShowContact(const Contact* pc); //Delete address book void DeleteContact(Contact* pc); //find contact void SearchContact(Contact* pc); //Modify contact void ModifyContact(Contact* pc); //Sort contacts void SortContact(Contact* pc); //Clear screen void ClsContact();
contact.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" void InitContact(Contact* pc) { assert(pc); pc->sz = 0; //data is a continuous space //memset(pc->data, 0, sizeof(pc->data)); Peoinfo* tmp = (Peoinfo*)malloc(DEFAULT_SZ * sizeof(Peoinfo)); if (NULL != tmp) { pc->data = tmp; } else { printf("InitContact()::%s\n", strerror(errno)); return; } pc->capacity = DEFAULT_SZ; } void DestroyContact(Contact* pc) { assert(pc); free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; } void check_capacity(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { //Capacity expansion Peoinfo* tmp = (Peoinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peoinfo)); if (NULL != tmp) { pc->data = tmp; pc->capacity += 2; printf("Successful expansion\n"); } else { printf("Check_Capacity()::%s\n", strerror(errno)); } } } void AddContact(Contact* pc) { assert(pc); //Check whether the capacity is expanded check_capacity(pc); //Enter contact printf("Please enter your name:>\n"); scanf("%s", pc->data[pc->sz].name); printf("Please enter age:>\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("Please enter gender:>\n"); scanf("%s", pc->data[pc->sz].sex); printf("Please enter the phone number:>\n"); scanf("%s", pc->data[pc->sz].tele); printf("Please enter the address:>\n"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("Contact added successfully\n"); Sleep(1000); system("cls"); } void ShowContact(const Contact* pc) { assert(pc); int i = 0; //A minus sign indicates left alignment printf("%-20s\t%-5s\t%-5s\t%-13s\t%-20s\n", "name", "Age", "Gender", "Telephone", "address"); for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-5d\t%-5s\t%-13s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr); } printf("Display successful\n"); } int FindByName(const Contact* pc, char name[]) { int i = 0; for ( i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name,name) == 0) { return i; } } return -1;//can't find } void DeleteContact(Contact* pc) { char name[NAME_MAX] = { 0 }; assert(pc); if (pc->sz == 0) { printf("Address book is empty,Cannot delete\n"); return; } printf("Please enter the name of the person to delete:>\n"); scanf("%s", name); //Find the specified contact int pos = FindByName(pc, name);//subscript if (pos == -1) { printf("The person to delete does not exist\n"); return; } else { //delete int j = 0; for ( j = pos; j < pc->sz-1; j++) //sz-1 if sz is 999, the biggest access is 998998 + 1 without crossing the boundary { pc->data[j] = pc->data[j + 1]; } pc->sz--; printf("Delete specified contact succeeded\n"); } } void SearchContact(Contact* pc) { char name[NAME_MAX] = { 0 }; assert(pc); if (pc->sz == 0) { printf("Address book is empty,Unable to find\n"); return; } printf("Please enter the name of the person you want to find:>\n"); scanf("%s", name); //Find the specified contact int pos = FindByName(pc, name);//subscript if (pos == -1) { printf("The person you are looking for does not exist\n"); return; } else { //A minus sign indicates left alignment printf("%-20s\t%-5s\t%-5s\t%-13s\t%-20s\n", "name", "Age", "Gender", "Telephone", "address"); printf("%-20s\t%-5d\t%-5s\t%-13s\t%-20s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } } void ModifyContact(Contact* pc) { char name[NAME_MAX] = { 0 }; assert(pc); if (pc->sz == 0) { printf("Address book is empty,Cannot modify\n"); return; } printf("Please enter the name of the person to modify:>\n"); scanf("%s", name); //Find the specified contact int pos = FindByName(pc, name);//subscript if (pos == -1) { printf("The person to modify does not exist\n"); return; } else { //Modify contact information printf("Please enter your name:>\n"); scanf("%s", pc->data[pos].name); printf("Please enter age:>\n"); scanf("%d", &(pc->data[pos].age)); printf("Please enter gender:>\n"); scanf("%s", pc->data[pos].sex); printf("Please enter the phone number:>\n"); scanf("%s", pc->data[pos].tele); printf("Please enter the address:>\n"); scanf("%s", pc->data[pos].addr); printf("Contact modified successfully\n"); } } int cmp_con_by_age(const void* e1, const void* e2) { return (((Peoinfo*)e1)->age - ((Peoinfo*)e2)->age); } void SortContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("Address book is empty,Unable to sort\n"); return; } qsort(pc->data, pc->sz, sizeof(Peoinfo), cmp_con_by_age); printf("Sorting complete:\n"); ShowContact(pc); } void ClsContact() { Sleep(1000); system("cls"); }