方法一:双指针
void GetMemory(char ** p, int num)
{
*p = (char *)malloc(num*sizeof(char));
}
int main()
{
char *str = NULL;
GetMemory(&str,10);
strcpy(str, “hello”); // C语言的字符串拷贝
free(str);
str = NULL;
return 0;
}
https://blog.csdn.net/a1232345/article/details/40216497
常见的内存问题和野指针
常见的错误
关于内存的一些知识已在内存分配中提及,现记录与分享常见的内存错误与对策。
类型 1:内存未分配成功,却使用了它。
方 法:在使用之前检查指针是否为NULL。
1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。
2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。
类型 2:引用了尚未初始化的指针
原 因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。
1)没有初始化的观念。
2)内存的缺省值是未定义,即垃圾值。
类型 3:越界操作内存
原 因:内存分配成功且初始了,但越界操作是不允许的。
例 如:在使用数组时经常发生下标“多1”或“少1”,特别是在for循环语句时。
类型 4:忘记释放内存,造成内存泄漏。
原 因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。
类型 5:释放了内存却继续使用它
原 因:对应的情况有2种
1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。
2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。
使用规则
为了保证代码的健壮和安全,可以参考如下的规则:
规则1:使用malloc申请的内存时,必须要立即检查相对应的指针是否为NULL。
规则2:初始化数组和动态内存。
规则3:避免数组或指针下标越界。
规则4:动态内存的申请和释放必须相配对,防止内存泄漏。
规则5:free释放某块内存之后,要立即将指针设置为NULL,防止产生野指针。
1.野指针
概念:“野指针”不是NULL指针,是指指向“垃圾”内存的指针。即指针指向的内容是不确定的。
产生的原因:1)指针变量没有初始化。因此,创建指针变量时,该变量要被置为NULL或者指向合法的内存单元。
2)指针p被free之后,没有置为NULL,让人误以为p是个合法的指针。
3)指针跨越合法范围操作。不要返回指向栈内存的指针或引用
2.内存泄漏
概念:用动态内存分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元,直到程序结束。
3.内存溢出
概念:系统分配的内存不足以放下数据,称为内存溢出。
https://blog.csdn.net/qq_38374864/article/details/79169271
flaot *p = new float(3.14);
delete p;
char *pt = new char[10];
delete[] pt; //指针前面添加[],表示对数组空间操作
https://blog.csdn.net/u013355826/article/details/60117069
默认的拷贝函数——即浅拷贝
当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象,所以,此时,必须采用深拷贝。
深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。
深拷贝指的就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用)时,对象的另开辟一块新的资源,而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值。
https://blog.csdn.net/u010700335/article/details/39830425
堆内存 栈内存
1、栈区(stack)—由编译器自动分配释放
2、堆区(heap)— 一般由程序员分配释放
3、全局区(静态区)(static)— 全局变量和静态变量的存储是放在一块的。程序结束后有系统释放
https://blog.csdn.net/abcjennifer/article/details/39780819
如果p是NULL指针,那么free对p 无论操作多少次都不会出问题。如果p不是NULL 指针,那么free对p连续操作两次就会导致程序运行错误。
memcpy:内存拷贝函数
函数原型:void *memcpy(void *dest, const void *src, size_t n);
功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
char *buf="My name is yanxiadong!";
char a[30]="This is a cup,good night!";
memcpy(a,buf+3,25);
用memset进行初始化
函数原型:void *memset(void *s,int ch,unsigned int n);
函数说明:将s中的前n个字节用ch替换并返回s。
char a[30];
memset(a,0,30);
https://blog.csdn.net/dongyanxia1000/article/details/50532325
成功时返回零,错误时返回非零值
https://cloud.tencent.com/developer/section/1009610
创建无头结点的链表
https://blog.csdn.net/LiuBo_01/article/details/80333693
C语言的标准内存分配函数:malloc,calloc,realloc,free等。
malloc与calloc的区别为1块与n块的区别:
malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。
realloc调用形式为(类型*)realloc(ptr,size):将ptr内存大小增大到size。
free的调用形式为free(voidptr):释放ptr所指向的一块内存空间。
C++中为new/delete函数。
https://blog.csdn.net/qq_35608277/article/details/79467539
当在函数内部使用sizeof()求解由函数的形参传入的字符数组的长度时,得到的结果为指针的长度,既对应变量的字节数,而不是字符串的长度,此处一定要小心。
https://blog.csdn.net/ljss321/article/details/51195125
实际上,传参时,也确实是把它当成一个指针来传递的,传递的就是一个首地址,所以你用sizeof求的值,就是指针长度
https://fishc.com.cn/thread-2502-1-1.html