Необработанное исключение в 0x0FC9E559 (ucrtbased.dll) в MyString.exe: 0xC0000005: Место записи нарушения прав доступа 0x00000000 - PullRequest
0 голосов
/ 02 марта 2019

У меня проблема с классом строк: «Необработанное исключение в функции strcpy».У меня нет большого опыта работы с указателями.Пожалуйста, дайте мне ваши рекомендации.Заранее спасибо!

Используется IDE: Visual Studio 2017

Необработанное исключение в 0x0FC9E559 (ucrtbased.dll) в MyString.exe: 0xC0000005: место записи нарушения прав доступа 0x00000000.

MyString.cpp:

#pragma warning(disable:4996)
#include "MyString.h"
#include "cstring"
#include <iostream>
using namespace std;

MyString::MyString()
{
    length = 0;
    content = NULL;
}

MyString::MyString(int length, const char* content) 
{
    this->length = length;
    this->content = new char[this->length + 1];
    strcpy(this->content, content);
}

MyString::MyString(const char* content)
{
    length = strlen(content);
    this->content = new char[length + 1];
    strcpy(this->content, content);
}

void MyString::setLength(int length) 
{
    this->length = length;
}

const int MyString::getLength() 
{
    return length;
}

void MyString::setContent(char* content) 
{
    strcpy(this->content, content); // Unhandled exception !!!
}

const char* MyString::getContent() 
{
    return content;
}

ostream& operator << (ostream& out, const MyString& string)
{

        out << "Content:\n" << string.content << "\n";
        out << "Length:\n" << string.length << "\n";

    return out;
}

const MyString operator+(MyString& string1, MyString& string2)
{
    MyString concatString;
    concatString.setLength(string1.length + string2.length);
    strcat(string1.content, string2.content);
    concatString.setContent(string1.content);

    return concatString;
}

MyString::~MyString()
{
    delete[] content;
}

MyString.h:

#include <iostream>
using namespace std;

class MyString
{
private:
    int length;
    char* content;

public:

    friend ostream& operator << (ostream& out, const MyString& anotherString);

    MyString(); // Constructor fara parametrii
    MyString(int, const char*); // Constructor cu 2 parametrii
    MyString(const char*); // Constructor cu 1 parametru

    friend const MyString operator+(MyString&, MyString&);

    // setters and getters
    void setLength(int);
    const int getLength();
    void setContent(char*);
    const char* getContent();

    // destructor
    ~MyString();
};

Main.cpp:

#include <iostream>
#include "MyString.h"
using namespace std;

int main() {

    MyString string1("---");
    MyString string2("..");

    cout << (string1 + string2);


    system("pause");
    return 1;
}

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Есть несколько проблем с этим кодом.

Во-первых, вам нужно реализовать правило 3 , чтобы также предоставить конструктор копирования и оператор присваивания.

Затем setLength() корректирует максимальную длину вашей строки, но она ничего не выделяет, так что вы можете создать переполнение буфера, или если конструктор по умолчанию использовал UB из-за nullptr.Это то, что происходит в вашем operator+().

Как только вы внедрили правило 3, быстрое исправление для оператора + может быть таким:

const MyString operator+(MyString& string1, MyString& string2)
{
    MyString concatString(string1.length + string2.length, string1.content);
    strcat(concatString.content, string2.content);

    return concatString;   // but this requires copy constructor to work
}

Вы для своего конструктора на основе длины, вы предполагаете, что длина больше, чем строка, котораяВы хотите скопировать.Так что либо вы утверждаете это, либо используете strncpy()

0 голосов
/ 02 марта 2019

In

const MyString operator+(MyString& string1, MyString& string2)
{
    MyString concatString;
    concatString.setLength(string1.length + string2.length);
    strcat(string1.content, string2.content);
    concatString.setContent(string1.content);

    return concatString;
}

concatString создается пустым, а setLength устанавливает только длину без (пере) выделенного содержимого , поэтомуВы strcpy пустой указатель в setContent

, вам также необходимо скопировать и объединить в concatString , а не в string1

Так например:

void MyString::setLength(int length) 
{
    if (length > this->length) {
      char * b = new char[length + 1];

      if (this->content != NULL) {
        strcpy(b, this->content);
        delete [] this->content;
      }
      this->content = b;
    }
    this->length = length;
}

const MyString operator+(const MyString& string1, const MyString& string2)
{
    MyString concatString;
    concatString.setLength(string1.length + string2.length);
    strcpy(concatString.content, string1.content);
    strcat(concatString.content, string2.content);

    return concatString;
}

setContent не может просто сделать strcpy , лучше сделать, например,

void MyString::setContent(char* content) 
{
  if (content == NULL) {
    if (this->content != NULL) 
      delete [] this->content;
    this->content = NULL;
    this->length = 0;
  }
  else {
    setLength(strlen(content));
    strcpy(this->content, content);
  }
}

После этих двух изменений компиляция и выполнение:

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra -g MyString.cpp Main.cpp 
In file included from MyString.cpp:2:0:
MyString.h:22:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     const int getLength();
                         ^
MyString.cpp:41:31: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
 const int MyString::getLength()
                               ^
In file included from Main.cpp:2:0:
MyString.h:22:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     const int getLength();

pi@raspberrypi:/tmp $ ./a.out
Content:
---..
Length:
5
sh: 1: pause: not found

и ниже valgrind

pi@raspberrypi:/tmp $ valgrind ./a.out
==6134== Memcheck, a memory error detector
==6134== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6134== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6134== Command: ./a.out
==6134== 
Content:
---..
Length:
5
sh: 1: pause: not found
==6134== 
==6134== HEAP SUMMARY:
==6134==     in use at exit: 0 bytes in 0 blocks
==6134==   total heap usage: 5 allocs, 5 frees, 21,261 bytes allocated
==6134== 
==6134== All heap blocks were freed -- no leaks are possible
==6134== 
==6134== For counts of detected and suppressed errors, rerun with: -v
==6134== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

Чтобы не иметь предупреждения во время компиляции, не возвращаются const int но просто int

Лучше иметь length , чтобы быть size_t, а не int

getLength и getContent может быть const (int getLength() const и const char* getContent() const)


Как Кристофговорит в замечании operator+ возвращает копию строкиg, и вы не определяете ни конструктор копирования, ни operator=.Когда класс содержит указатели, его необходимо определить, а в недавнем C ++ также move

...