c/c++整理--引用和指针(5)

偏执的太偏执、 2022-07-03 13:55 279阅读 0赞

一、什么是“野指针”

  “野指针”不是NULL指针,而是指向“垃圾”内存的指针,其成因主要为:指针变量没有被初始化,或指针p被free或者delete之后,没有置为NULL。

二、“野指针”的危害

下面程序有什么重大的bug?

  1. short *bufptr;
  2. short bufarray[20];
  3. short var = 0x20;
  4. *bufptr = var;
  5. 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所指向的一块内存空间。

五、找错——动态内存的传递

  1. #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行改为

  1. name = new char[strlen(classname)+1];

其次,20行newname是在栈中的,函数结束后就被自动释放了,应该在堆中分配内存。改为

  1. char *newname = new char[strlen(name)+1];

六、动态内存分配

  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行出现段错误。

这里可以使用函数返回值来避免这个问题,

  1. char * GetMemory(char *p, int num)
  2. {
  3. p = (char*)malloc(sizeof(char)*num);
  4. return p;
  5. }
  6. .......
  7. str = GetMemory(str, 10);

七、内存分配方式有几种

(1)从静态存储区分配。在程序编译时就已分配好,例:全局变量。

(2)从栈上分配。函数中的局部变量的存储单元可以在栈上分配,函数结束时,这些变量被自动释放。

(3)从堆上分配。用malloc或free申请内存,由程序员决定其生存周期,然后执行free或delete。

发表评论

表情:
评论列表 (有 0 条评论,279人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++指针引用

    引用 是内存空间另外一个别名,相当于门牌号,可以用它来找到具体的内存空间。 int i = 17; int &b = i; cout << b

    相关 指针引用

    1.指针和引用的差别 (1)非空区别:任何情况下都不能使用指向空值的引用。一个引用总是指向某些对象。如果声明一个变量并让它指向一个对象,但是该变量某些时候可能也不指向任何对

    相关 引用指针区别

    将“引用”作为函数参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对

    相关 指针引用

    1、引用 1. 引用必须初始化 引用就是给对象取一个别名。定义引用,程序把引用和它的初始值绑定在一起(绑定之后不可再绑定其他对象),而不是初始值拷贝引用,为