一、什么是“野指针”
“野指针”不是NULL指针,而是指向“垃圾”内存的指针,其成因主要为:指针变量没有被初始化,或指针p被free或者delete之后,没有置为NULL。
二、“野指针”的危害
下面程序有什么重大的bug?
short *bufptr;
short bufarray[20];
short var = 0x20;
*bufptr = var;
bufarray[0] = var;
第一行bufptr声明了一个指针,但没有初始化,这个时候bufptr是乱指的一个指针,即“野指针”,第四行取一个非法地址的值就会造成程序崩溃,甚至是段错误。
三、有了malloc/free,为什么还要new/delete
malloc/free是c++/c的标准库函数,new/delete是c++的运算符,都可以申请和释放堆内存。
对于内部的数据类型,如int、char等,malloc/free和new/delete都可进行申请和释放,但是对于c++中的类数据类型,malloc/free无法满足要求了,对象在销亡之前要执行析构函数,malloc/free是库函数不是运算符,不能把执行构造函数和析构函数的任务强加于其。
四、各种内存分配和释放的函数的联系和区别
malloc、calloc、realloc、free
(1)malloc与calloc的区别为1块和n块的区别。
(2)malloc的调用形式为(类型*)malloc(size),在堆内存中分配一块size大小的连续内存,返回该区域的首地址。此时内存中的值没有被初始化;
(3)calloc的调用形式为(类型*)calloc(n,size),在堆内存中分配n块size大小的连续内存,返回首地址,此时内存中的值被初始化为0;
(4)realloc的调用形式为(类型*)realloc(*ptr,size),将ptr的内存大小增大到size,新增的内存没有初始化。
(5)free的调用形式为free(void* ptr),释放ptr所指向的一块内存空间。
五、找错——动态内存的传递
#include <iostream>
using namespace std;
class Base
{
char* name;
public:
Base(char* classname)
{
name = new char[strlen(classname)];
strcpy(name, classname);
}
~Base()
{
delete name;
}
char* copyname()
{
char newname[10] = "";
strcpy(newname, name);
return newname;
}
char* getname()
{
return name;
}
};
class Subclass : public Base
{
public:
Subclass(char* classname) : Base(classname)
{
}
};
int main()
{
Base* pBase = new Subclass("test");
printf("name:%s\n", pBase->getname());
printf("new name: %s\n", pBase->copyname());
return 0;
}
这里strlen测得的大小为实际字符串大小小1,所以11行改为
name = new char[strlen(classname)+1];
其次,20行newname是在栈中的,函数结束后就被自动释放了,应该在堆中分配内存。改为
char *newname = new char[strlen(name)+1];
六、动态内存分配
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
void GetMemory(char *p, int num)
{
p = (char*)malloc(sizeof(char)*num);
}
int main()
{
char* str = NULL;
GetMemory(str, 10);
strcpy(str, "hello");
return 0;
}
这里的GetMemory函数有问题,GetMemory函数体中的p实际上是main函数中的str变量在GetMemtory函数栈中的一个备份,因为编译器总是为函数的每个参数制作临时的变量。因此,虽然在函数中重新分配了内存,但是返回main函数时,str还是NULL,14行出现段错误。
这里可以使用函数返回值来避免这个问题,
char * GetMemory(char *p, int num)
{
p = (char*)malloc(sizeof(char)*num);
return p;
}
.......
str = GetMemory(str, 10);
七、内存分配方式有几种
(1)从静态存储区分配。在程序编译时就已分配好,例:全局变量。
(2)从栈上分配。函数中的局部变量的存储单元可以在栈上分配,函数结束时,这些变量被自动释放。
(3)从堆上分配。用malloc或free申请内存,由程序员决定其生存周期,然后执行free或delete。