使用 valgrind - "Invalid read of size 1" for strlen

Using valgrind - "Invalid read of size 1" for 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== 

您认为需要添加终止符 0 的假设是错误的,strcpy() 会为您完成。您这样做的尝试在您分配的 space 之后添加了一个字节的 0 终止符(记住,数组索引从零开始),并且语法也是错误的,您需要这样做:

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

但是,要修复内存泄漏,您需要删除之前的字符串,例如

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;
}

现在,为了让它工作,您还需要修复构造函数和复制构造函数以初始化名称成员,因此它不是第一次调用 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 而不是当前处理字符串的低级别方式,这样您甚至不需要为此 class 实现复制构造函数、赋值运算符和析构函数,也不处理正确管理内存的问题。