使用valgrind - "读取大小为1"对于strlen

时间:2017-05-20 22:43:15

标签: pointers memory-leaks valgrind strlen

我试图编写将Student对象的名称设置为新名称的代码,但是我在创建字符数组时遇到了内存泄漏错误。我假设它与数组末尾的/ 0有关,并且没有正确终止,但我不知道如何正确解决这个问题。谢谢您的帮助。

#include "student.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

Student::Student(const char * const name, int perm) {
  this->setName(name);
  this->setPerm(perm);
}

int Student::getPerm() const {
  return this->perm;
}

const char * const Student::getName() const {
  return this->name;
}

void Student::setPerm(const int perm) {
  this->perm = perm;
}

void Student::setName(const char * const newName) {
  this->name = new char[strlen(newName)+1];
  // this->name[srtlen(newName)+1] = '/0';  <---- My suggested fix, but doesn't work
  strcpy(this->name,newName);

}


Student::Student(const Student &orig) {
  this->setName(orig.getName());
  this->setPerm(orig.getPerm());
}

Student::~Student() {
  delete this->name;
  this->perm = 0;
}

这是valgrind错误:

==13814== Invalid read of size 1
==13814==    at 0x4C2BA12: strlen (vg_replace_strmem.c:454)
==13814==    by 0x4F56FD6: UnknownInlinedFun (char_traits.h:267)
==13814==    by 0x4F56FD6: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.h:456)
==13814==    by 0x401ED8: Student::toString[abi:cxx11]() const (student.cpp:64)
==13814==    by 0x401A46: main (testStudent00.cpp:14)
==13814==  Address 0x5302e8 is not stack'd, malloc'd or (recently) free'd
==13814== 

1 个答案:

答案 0 :(得分:2)

您认为需要添加0终止符是错误的,strcpy()会为您执行此操作。你这样做的尝试将0终结符添加到你分配的空间之后一个字节(记住,数组索引从零开始),语法也是错误的,你需要这样做:

 this->name[strlen(newName)] = '\0';

但是,要修复内存泄漏,您需要删除上一个字符串,例如

void Student::setName(const char * const newName) 
{
   delete [] this->name;
   this->name = new char[strlen(newName)+1];
   strcpy(this->name,newName);
}

Student::Student(const Student &orig) : 
   name(0) {
  this->setName(orig.getName());
  this->setPerm(orig.getPerm());
}

Student::~Student() {
  delete [] this->name;
  this->perm = 0;
}

现在,为了使其工作,您还需要修复构造函数和复制构造函数以初始化name成员,因此它不是第一次调用setName()函数的未初始化指针,并且您需要添加也是一个赋值运算符,因此您可以正确处理赋值。

Student::Student(const char * const name, int perm) :
  name(0) 
{
  this->setName(name);
  this->setPerm(perm);
}

Student &operator=(const Student &orig) {
  this->setName(orig.getName());
  this->setPerm(orig.getPerm());
}

另外,考虑使用std::string而不是当前处理字符串的低级方式,这样你甚至不需要为这个类实现复制构造函数,赋值运算符和析构函数,也不需要正确管理存储器中。