考虑到数组不能定死,因此需要动态开辟空间。
int val=20; char arr[10]={0};
栈区:局部变量,函数形参
堆区:malloc,calloc,free,realloc
静态区(数据段):全局变量,静态变量
void* malloc(size_t size);
malloc这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
int main() { //假设开辟10个整型的空间 --10*sizeof(int) int* p=(int*)malloc(10*sizeof(int)); if(p==NULL) { perror("main");///main:xxxx return 0; } //使用 int i=0; for(int i=0;i<10;i++) { *(p+i)=i; } for(int i=0;i<10;i++) { printf("%d\n",p[i]); } free(p);///回收空间,p指针不会被默认为空指针。 p=NULL;//重要!!自己动手把指针置为NULL return 0; }
free 用来释放动态开辟的内存
如果参数ptr指向的空间不是动态开辟的,则free函数的行为是未定义的。
int main() { int a=10; int *p=&a; free(p);//!! }
如果ptr是NULL指针,则函数什么事都不做。
开辟一块空间并且初始化为0.
void* calloc(size_t num,size_t size) { } //num---需要元素的个数 //一个元素的大小
void* realloc(void* memblocks,size_t size); memblock---前面开辟的内存空间起始地址 size--新的大小
int main() { int* p=(int*)malloc(10*sizeof(int)); if(p==NULL) { perror("main"); return 1; } int i=0; for(int i=0;i<10;i++) { *(p+i)=5; } //还需要5个,这里需要p指向的空间更大,需要20个int空间 //realloc 调整空间 realloc(p,20*sizeof(int));///新的大小 ///返回重新调整后的内存块指针 //p=realloc(p,20*sizeof(int));///!!! 可能偷鸡不成蚀把米 //拿临时指针 int* ptr=realloc(p,20*sizeof(int)); if(ptr!=NULL) p=ptr; free(p); p=NULL; return 0; }
int main() { int* p=(int*)realloc(NULL,40);//这里功能类似malloc }
int main() { int *p=(int*)malloc(1000000000*sizeof(int)); //if(p==NULL) for(int i=0;i<10;i++) { *(p+i)=i;///非法访问内存 } return 0; }
int main() { int* p=(int*)malloc(10*sizeof(int)); if(p==NULL) { return 1; } int i=0; for(i=0;i<40;i++) { *(p+i)=i; } free(p); return 0; }
int main() { int arr[10]={0}; int* p=arr; //使用 free(p);//对非动态开辟空间使用free p=NULL; }
int main() { int *p=malloc(10*sizeof(int)); if(p!=NULL) return 1; for(int i=0;i<5;i++) { *p++=i; } free(p); p=NULL; }
int main() { int* p=(int*)malloc(100); //使用 //释放 free(p); //释放 free(p); return 0; }
void test { int* p=(int*)malloc(100); if(p==NULL) { return; } //使用 } int main() { test(); //... return 0; }
void GetMemory(char *p) { p = (char *)malloc(100); } //改: char* GetMemory(char *p) { p = (char *)malloc(100); return p; } //改: void GetMemory(char** p) { *p = (char *)malloc(100); } GetMemory(&str); void Test(void) { char *str = NULL; str=GetMemory(str); strcpy(str, "hello world"); printf(str);//?ok printf("hello world");//本质是传过去h的地址 free(str); }
值传递
p指针malloc后指向申请的空间
但是str仍然是NULL
归类维为:返回栈空间地址的问题
char *GetMemory(void) { char p[] = "hello world"; return p;//char* tmp=p; return tmp; } void Test(void) { char *str = NULL; str = GetMemory(); ///这里就要开始认为,结束栈帧后里面的东西就给“销毁了”。出现这种情况一律认为不行 printf(str); } int main() { Test(); }
野指针问题
没有free
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); }
void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); if(str != NULL) { strcpy(str, "world"); printf(str); } } ///提前free.
总的来说
对开始讲到的static修饰局部变量:
实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就
销毁。
但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁。
所以生命周期变长。
C99中,结构中的最后一个元素允许是未知大小的数组,这个称为[柔性数组]成员。
struct S { int n; int arr[];//大小是未知的 }; struct S { int n; int arr[0];//柔性数组成员 }; //两者都可以 int main() { struct S s={0};//这样创建arr是没法使用的 printf("%s\n",sizeof(s));///4 //期望arr的大小是10个int struct S* ps=(struct S*)malloc(sizeof(struct S)+10*sizeof(int)); //增加 struct S* ptr=(struct S*)realloc(ps,sizeof(struct S)+20*sizeof(int)); if(ptr!=NULL) { ps=ptr; } free(ps); ps=NULL; return 0; }
struct S{ int n; int* arr; }; int main() { struct S* ps=(struct S*)malloc(sizeof(struct S)); if(ps==NULL) return 1; ps->n=10; ps->arr=(int*)malloc(10*sizeof(int)); if(ps->arr==NULL) { return 1; } int i=0; for(i=0;i<10;i++) ps->arr[i]=i; //增加 int* ptr=realloc(psr->arr,20*sizeof(int)); if(ptr!=NULL) { ps->arr=ptr; } //使用 //释放 free(ps->arr); ps->arr=NULL; free(ps); ps=NULL; }