将指针设置为null会导致我的C ++程序崩溃

时间:2010-07-07 12:38:39

标签: c++ pointers

我有一个构造函数,它接收一个字符指针。如果它是空的,我需要将其成员变量设置为NULL,但是,当我尝试时程序在退出时崩溃。

我已经确认它到达了将其设置为NULL的行,这是导致崩溃的原因。

我尝试了以下内容:

val = NULL;

val = 0;

val = "";

这些都导致崩溃,但是如果我使用:

val = new Char[1];
val = "o";
它并没有崩溃。

有什么我不做的事吗?

更新

以下是我的问题的快速更新。

我正在使用的析构函数是:

~LField() { 
    if (val)
      delete[] val;
}

如果我拿出来:

if (val)
  delete[] val;

然后程序在退出时不会崩溃:

val = "";

以下是更多代码:

LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = "", bool canEditVal = true) { 
    if(strlen(valVal) > 0) {            
      //doesn't jump in here since valVal is empty
    }
    else {
      val = ""; // this is where I'm trying to set a NULL value
    }
}

LField(const LField &clone) { 
  if (val)
    delete[] val;

  val = new char[strlen(clone.val)]; 
  strcpy(val, clone.val);
  rowNum = clone.rowNum;
  colNum = clone.colNum;
  width = clone.width;
  canEdit = clone.canEdit;
  index = clone.index;
}

LField& operator=(const LField &lfieldobj) {
    if (this != &lfieldobj) {
    if (val)
       delete[] val;

    val = new char[strlen(lfieldobj.val)];
    strcpy(val, lfieldobj.val);
    rowNum = lfieldobj.rowNum;
    colNum = lfieldobj.colNum;
    width = lfieldobj.width;
    canEdit = lfieldobj.canEdit;
    index = lfieldobj.index;
   }

   return *this;
}

修改:

LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = NULL, bool canEditVal = true) { 
    if(valVal != NULL) {            

    }
    else {
      val = NULL; 
    }
}

LField(const LField &clone) { 
  delete[] val;
  if (clone.val != NULL) {
     val = new char[strlen(clone.val) + 1]; 
     strcpy(val, clone.val);
  }
  else
    val = NULL;
  rowNum = clone.rowNum;
  colNum = clone.colNum;
  width = clone.width;
  canEdit = clone.canEdit;
  index = clone.index;
}

LField& operator=(const LField &lfieldobj) {
    if (this != &lfieldobj) {
       delete[] val;
    if (lfieldobj.val != NULL) {                
       val = new char[strlen(lfieldobj.val) + 1];
       strcpy(val, lfieldobj.val);
    }
    else
       val = NULL;
    rowNum = lfieldobj.rowNum;
    colNum = lfieldobj.colNum;
    width = lfieldobj.width;
    canEdit = lfieldobj.canEdit;
    index = lfieldobj.index;
   }

   return *this;
}

~LField() { 
      delete[] val;
}

我已经更新了代码。现在val要么用new []分配内存,要么是NULL,所以delete []不应该有问题。但是,它在退出时仍会崩溃。

5 个答案:

答案 0 :(得分:10)

在复制构造函数中,您尝试delete[]未初始化的指针:

LField(const LField &clone) { 
  //good code here, then...
  if (val) //<+ some random address here
    delete[] val;//<-undefined behavior
}

不要那样做,跳过整个构造。在单元化对象上调用复制构造函数,没有资源可以“释放”。

此外,您尝试delete[]字符串文字,这是未定义的行为。请尝试以下更改:

LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = "", bool canEditVal = true) { 
    if(strlen(valVal) > 0) {            
      //doesn't jump in here since valVal is empty
    }
    else {
      val = new char[1];
      *val = 0;
    }
}

以下是缓冲区溢出:

val = new char[strlen(whatever)];  <-forgot to +1 for the null terminator
strcpy(val, whatever);

在不需要delete[]之前检查空指针 - 空指针上的delete[]是合法的并且没有效果。

答案 1 :(得分:4)

亲爱的,从哪里开始?

一个:

LField(const LField &clone) { 
  if (val)
    delete[] val;

这是愚蠢的,因为val未定义。您将在随机存储器上调用delete []。

B:

  val = new char[strlen(clone.val)]; 
  strcpy(val, clone.val);

c-type字符串需要一个null终止符。你需要新的[]和附加字节。

答案 2 :(得分:3)

您可能正在尝试访问代码中的某个位置(取消引用)val仍然引用NULL

确保您的代码中没有位置

  val=NULL; //in the constructor

  //somewhere in your code      
  char ch= *val; //This would be Undefined Behavior

修改

您正在delete[]上调用val,其值为""(字符串文字),这是未定义的行为。

UB的一些例子

 1)
   char *p="hello";
  delete p; //UB
  delete []p; //UB

 2)
  char *p==new char[20]("Hello");
  delete p; //UB
  delete []p; //fine

 3) 
  char *p=new char('a');
  delete []p; //UB
  delete p; //fine

答案 3 :(得分:2)

调用

delete[] NULL;
delete[] 0;

没关系,你甚至不需要空检查。 但是打电话给

delete[] "whatever"; 

不正常,因为此char *未使用new []分配。

请注意,调用字符串函数(如strlen()就像在构造函数中完成一样,在null引用中是非法的。

在第一次分配之前,您可以在构造函数中访问val。这也可能导致未定义的行为。

答案 4 :(得分:0)

我和Prasoon Saurav在一起。您展示的代码看起来不错,所以问题出在其他地方。

试试这个:

  1. 将其更改回val = 0;
  2. 删除 all 您的代码,但构造函数,析构函数和该类对象的声明除外。注释所有其他。我打算好好表示它不会崩溃。
  3. 慢慢取消注释其他代码并重试该程序。当它再次崩溃时,你找到了罪魁祸首。