1.
静态内存
编译的时候预申请的内存,不需要自己管理,所属函数执行完毕后自动回收
缺陷:
类似下面的函数会出错:
char *uppr(char *oldstring) { char newstring[100]; ... return newstring; }
因为函数执行完毕后字符数组new已经被销毁了,指针指向的位置当然就不是正确的地址。
此函数可以通过以下方式解决:
void uppr(char *old,char *new) { ... }
可以将两个字符数组传入,然后将更改写回new中。
可以实现的原因是new 所代表的数组地址是主函数定义的,更改不会随着子函数销毁而销毁,因此在子函数中对主函数变量指针的改变可以实现,经典实现就是双返回的交换
如下:
void swap(int *a,int *b) { int c; c=*a; *a=*b; *b=c; } 调用 swap(&a,&b);
2.
溢出
使用了超出已申请的内存,就是在申请数组是100个元素的情况下写入了101及以上个元素,或企图读取到101个及以上位置的元素
引用错误的结果不可预期,通常安全性都出自溢出区,读取了本来不能读取的位置而启动了另外的程序。
写入的错误可能会导致其他程序的数据被覆盖,程序也会出现错误。
解决方式:
通常是在进行操作时判断空间大小,进行截取,即将超出部分删除,但是这样会导致数据丢失
3.
动态内存
在程序运行过程中动态进行分配的内存,通常是自己申请
主要函数
#include<stdlib.h> void *malloc(size_t size) void *calloc(size_t nmemb,size_t size)
释放内存 void *free(void *ptr)
调整内存 void *realloc(void *ptr,size_t size)
注意动态内存的释放不由系统决定,而是必须使用free函数才能释放,因此在子函数中可以返回指向申请的内存的指针
例如:
char *uppr(char *old) { char *new; if(new=malloc(strlen(old)+1)){ strcpy(new,old); int i; for(i=0;i<strlen(new);++i){ if(new[i]>=97 && new[i]<=122){ new[i]-=32; } } }else{ exit(255); } return new; }
此时子函数执行完毕后new并不会被销毁,因此可以返回此地址,但是在使用完毕后最好将他是free掉。
另外,realloc函数当ptr为NULL时,等价于malloc,size为0时,相当于free
注意free后指针变为悬空指针,不可以访问(不是不能,访问悬空指针会发生不可预知的异常)。
4.
分配堆栈
#include<stdlib.h> void *alloca(size_t size)
此时分配的内存在函数结束时被自动收回,一般很少用
5.
内存锁定
一般情况下,如果内存一段时间内不使用,系统会自动将其转移到磁盘上原位置放置新数据,如果想禁止此区域被转移,可以使用内存锁定
常用函数为
#include<sys/types.h>//锁定内存首地址+长度 int mlock(const void *addr,size_t length);//解锁内存,首地址+长度 int munlock(void *addr,size_t lemgth);/*锁定内存页,flag选项:*MCL_CURRENT 所有内存页*MCL_FUTURE 所有为进程添加的地址页*/int mlockall(int flag); int munlockall(void);
(以上函数只限root用户)