С++ memcpy/strcpy указателя char на указатель char члена класса

у меня есть собственный класс, назовем его Student и основной метод. Я создаю экземпляр класса и просто хочу вывести содержимое класса.

Моя программа вылетает с ошибкой: Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

Фактический код

Студент.ч

#ifndef PROG2_STUDENT_H
#define PROG2_STUDENT_H

#include <iostream>

class Student
{
private:
    char *name;

    char *firstName;

    unsigned matriculationNumber;

    unsigned semester;

public:
    Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester);

    ~Student();

    friend std::ostream &operator<<(std::ostream &ostream, const Student &student);
private:
};

#endif

Студент.cpp

#include <cstring>
#include "Student.h"

Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
    std::strcpy(this->name, name);
    std::strcpy(this->firstName, firstName);

    this->matriculationNumber = matriculationNumber;
    this->semester            = semester;
}

Student::~Student()
{
    delete[] this->name;
    delete[] this->firstName;
}

std::ostream &operator<<(std::ostream &stream, const Student &input)
{
    stream << input.name << ", " << input.firstName << ": "
           << input.semester << " Semester, MA " << input.matriculationNumber;

    return stream;
}

и мой главный

#include <iostream>
#include "StudentPackage/Collection/StudentCollection.h"

int main()
{
    Student studentOne((char *)"Testerson", (char *)"Test", 12345, 2);
    std::cout << studentOne << std::endl;

    return 0;
}

Что я пробовал

Я пробовал несколько вещей, включая memcpy. Но с memcpy я не могу правильно определить размер массива символов.

Когда я меняю студенческий конструктор на следующий, у меня возникают проблемы с удалением/освобождением в деструкторе. Я предполагаю, что это в любом случае неправильный путь, но это происходит, потому что область видимости входных переменных уничтожается до вызова деструктора класса, верно?

Student::Student(char *name, char *firstName, unsigned matriculationNumber, unsigned semester)
{
    this->name      = name;
    this->firstName = firstName;

    this->matriculationNumber = matriculationNumber;
    this->semester            = semester;
}

Вопрос

  1. Как я могу правильно скопировать массив символов из конструктора (имя в это имя)?
  2. Как я могу правильно скопировать массив символов из конструктора (firstName в this->firstName)?

person Ulf Tietze    schedule 22.05.2021    source источник
comment
Вы забыли выделить память.   -  person molbdnilo    schedule 22.05.2021
comment
Параметры должны быть const char*, а не char*. (Я подозреваю, что вы получили ошибку компиляции, но исправили ее не в том месте.)   -  person molbdnilo    schedule 22.05.2021
comment
1) Даже если std::strcpy выделена память, вы никогда не должны использовать delete[] для чего-либо, что не было получено с помощью new T[n]. 2) Используйте std::string.   -  person Evg    schedule 22.05.2021
comment
Но почему (const char*)? Что делать, если я хочу реализовать такой метод, как: changeName(char* newName)? Можно ли также объявить const char* newName?   -  person Ulf Tietze    schedule 22.05.2021
comment
@Evg Я бы хотел использовать std::string, но это инструкция моего профессора ^^ Я должен построить вокруг этого. Но что вы имеете в виду под new T[n]? Зачем мне здесь оператор new?   -  person Ulf Tietze    schedule 22.05.2021
comment
Если вы хотите управлять памятью вручную, у вас есть несколько возможностей, но функции выделения и освобождения всегда должны совпадать друг с другом. Если вы выделяете с помощью new, вы используете delete, если вы выделяете с помощью new[], вы используете delete[], если вы выделяете с помощью malloc(), вы используете free(). std::strcpy() не выделяет память: вы несете ответственность за предоставление достаточно большого буфера, т. е. вы должны сначала инициализировать this->name чем-то значимым. Не забывайте о пробеле для завершающего нулевого символа.   -  person Evg    schedule 22.05.2021
comment
Можно ли также объявить const char* newName? - Да, если changeName(x) не должен изменять буфер, на который указывает x, и я думаю, что это не так.   -  person Evg    schedule 22.05.2021


Ответы (1)


std::strcpy не выделяет память. Таким образом, ваша программа копирует входные данные по мусорному адресу, который находится в области памяти, где находится ваш объект Student. И в результате неудивительно, что в результате вы получаете нарушение сегмента. Есть два решения:

  • способ в стиле C - выделить память вручную (т.е. как auto n = std::strlen(name); this->name = new char[n + 1]; std::strcpy(this->name, name);), но потом нужно удалить ее вручную (т.е. delete name;) в деструкторе. Кстати, n + 1, поскольку вам также нужно место для нулевого терминатора, результат strlen не включает его.
  • намного лучше и больше С++ - используйте std::string (т.е. объявляйте переменную-член name как std::string). Тогда вы просто можете сделать присваивание: this->name = name;, и не нужно ручное управление памятью - std::string позаботится.
  • (Стиль кода) Также рекомендуется использовать какой-либо префикс или постфикс для переменных-членов, например, m_name (больше стиля Microsoft) или name_ - больше стиля Google, чтобы избежать этих ненужных this->.
person ivan.ukr    schedule 22.05.2021