Структуры и двойные указатели внутри других структур, многослойная путаница

Итак, у меня есть три Struct с функциями, чтобы работать с ними ...

struct Song{
    std::string songTitle;
    std::string songLength;
};
Song* createSong(string title, string length);
void displaySong(Song* s);
void destroySong(Song* s);

struct CD{
    std::string cdArtist;
    std::string cdTitle;
    int cdYear;
    int cdRate;
    int cdNumSongs;
    Song** songs;
};
CD* createCD(std::string artist, std::string title, int year, int rate, int numSongs);
void displayCD(CD* c);
void destroyCD(CD* c);
void addSong(CD* cd, std::string title, std::string length);

struct CDs{
    CD** cdArray;
    int cdMaxSize=1000;
    int cdCurrentSize=0;
};
CDs* createCDs (const char* filename);
void displayCDs (CDs* c);
void destoryCDs (CDs* c);

Я создал и протестировал функции struct Song, а также функции struct CD. Однако у меня возникли проблемы с внедрением CD * createCD (const char * filename), который принимает вещи из файла и создает динамически сохраняемый массив из этих компакт-дисков.

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

Код пока ...

CDs* createCDs(const char* filename){
    CDs* cds = new CDs;
    ifstream inFile(filename);

    CD* tempcd;
    CD** tempcdArray = new CD*[cds->cdCurrentSize];
    CD** tempcdNewArray;

    string tempArtist, tempTitle, tempSongTitle, tempSongLength;
    int tempYear, tempRate, tempNumSongs;

    while(getline(inFile, tempTitle)){ // WHEN IT GRABS NOTHING
        cds->cdMaxSize++;
        tempcdNewArray = new CD*[cds->cdMaxSize];
        for(int i=0; i<cds->cdCurrentSize; i++){
            tempcdNewArray[i] = tempcdArray[i];
            delete[] tempcdArray;
        }

        getline(inFile, tempArtist);
        inFile>>tempYear;
        inFile>>tempRate;
        inFile>>tempNumSongs;
        inFile.ignore();
        tempcd = createCD(tempArtist, tempTitle, tempYear, tempRate, tempNumSongs);
        for(int i=0; i<tempNumSongs; i++){
            getline(inFile, tempSongLength, ',');
            getline(inFile, tempSongTitle);
            addSong(tempcd, tempSongTitle, tempSongLength);
        }

        tempcdNewArray[cds->cdCurrentSize] = tempcd;
        tempcdArray = new CD*[cds->cdMaxSize];
        for(int i=0; i<cds->cdMaxSize; i++){
            tempcdArray[i] = tempcdNewArray[i];
            delete tempcdNewArray;
        }
        delete[] tempcd;
        cds->cdCurrentSize++;

    }
    for(int i=0; i<cds->cdCurrentSize; i++){
        cds->cdArray[i] = tempcdArray[i];
    }
    inFile.close();
    return cds;
}

Если вам нужно знать, Один компакт-диск в макете текстового файла - ..

Eternal Tears of Sorrow (cd title)
Saivon Lapsi (cd artist)
2013 (cd year)
7 (cd rating)
13 (number of songs)
1:10,Saivo (length, title)
... (other songs after here)

Я попытался отследить свой код на предмет висящих указателей, я убедился, что я «обновил» все разделы памяти, которые возвращаю ... и т. д. И т. Д.

Зачем тебе все new? Просто вернитесь по значению, а не по указателю.

Cory Kramer 29.10.2018 20:10

Есть ли требование не использовать подходящий контейнер? Пара std::vector поверх другого предложения использовать объекты вместо указателей значительно упростит это. Это также предотвратит утечку памяти, когда возникнет исключение после того, как вы в противном случае что-то сделали бы new.

chris 29.10.2018 20:13

«Я удостоверился, что я« обновил »все разделы памяти, которые возвращаю… и т. д.» Я немного озадачен, почему вы думаете, что «новое» все хорошо. Вы должны сделать наоборот: убедитесь, что у вас нет ничего new.

463035818_is_not_a_number 29.10.2018 20:18

Добро пожаловать в Stack Overflow. Когда вы пишете код, неплохо было бы начать с чего-то небольшого и простого, которое отлично работает, а затем постепенно наращивать его. Здесь вы написали сразу много кода, и он не работает. И вы не дали нам достаточно, чтобы воспроизвести ошибку, даже если мы обнаружим ошибки некоторые, мы не можем быть уверены, что нашли все из них.

Beta 29.10.2018 20:45

Вы удаляете вещи внутри циклов for, к которым вы все еще обращаетесь на следующей итерации.

1201ProgramAlarm 29.10.2018 23:05

Очевидно, ваш delete не соответствует вашему new. Вы делаете один new[] и несколько delete[]. Кроме того, вы никогда не выделяете память для указателей внутри вашего массива. При удалении вы удаляете весь массив несколько раз (а не каждый элемент, за которым следует массив). Мне кажется, что у вас много бесполезных переменных. Вы не загадываете с памятью и надеетесь, что она сработает. Если это не домашнее задание для изучения распределения памяти и указателей на указатели, лучше вместо этого использовать дизайн, основанный на STL.

Phil1970 30.10.2018 01:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
106
1

Ответы 1

Я бы держался подальше от new / delete как можно дольше, а также переместил бы функции, работающие с вашими структурами, в в структуры или, по крайней мере, сделал бы их дружественными функциями. Используйте стандартный контейнер (например, std :: vector) для хранения. Я заменил ваши функции чтения и отображения объектов операторами потока, чтобы упростить чтение / запись с использованием стандартных потоков. Предполагается, что это будет читать файлы в указанном вами формате, а затем передавать созданные объекты в std :: cout в том же формате, что и в исходных файлах.

#include <iostream>
#include <vector>
#include <fstream>
#include <iterator>

class Song {
    std::string m_title;
    std::string m_length;
public:
    Song() : m_title(), m_length() {}
    friend std::ostream& operator<<(std::ostream&, const Song&);
    friend std::istream& operator>>(std::istream&, Song&);
};

std::ostream& operator<<(std::ostream& os, const Song& song) {
    os << song.m_length << "," << song.m_title;
    return os;
}

std::istream& operator>>(std::istream& is, Song& song) {
    std::string tmp;
    std::getline(is, tmp);
    std::string::size_type comma = tmp.find(",");
    if (comma != std::string::npos) {
        std::copy(tmp.cbegin(), tmp.cbegin()+comma, std::inserter(song.m_length, song.m_length.end()));
        std::copy(tmp.cbegin()+comma+1, tmp.cend(), std::inserter(song.m_title, song.m_title.end()));
    }
    return is;
}

class CD {
    std::string m_artist;
    std::string m_title;
    int m_year;
    int m_rate;
    std::vector<Song> m_songs;
public:
    CD() :
        m_artist(),
        m_title(),
        m_year(),
        m_rate(),
        m_songs()
    {}
    size_t size() { return m_songs.size(); }
    friend std::ostream& operator<<(std::ostream&, const CD&);
    friend std::istream& operator>>(std::istream&, CD&);    
};

std::ostream& operator<<(std::ostream& os, const CD& cd) {
    os << cd.m_title << "\n" << cd.m_artist << "\n" << cd.m_year << "\n"
       << cd.m_rate << "\n" << cd.m_songs.size() << "\n";
    for(const Song& song : cd.m_songs) {
        os << song << "\n";
    }
    return os;
}

std::istream& operator>>(std::istream& is, CD& cd) {
    int no_songs;
    std::getline(is, cd.m_title);
    std::getline(is, cd.m_artist);
    is >> cd.m_year;
    is >> cd.m_rate;
    is >> no_songs;
    is.ignore(); // discard rest of line
    cd.m_songs.reserve(no_songs);
    while(no_songs--) {
        Song a_song;
        is >> a_song;
        cd.m_songs.emplace_back(std::move(a_song));
    }
    return is;
}

class CDs {
    std::vector<CD> m_cds;
public:
    CDs() : m_cds() {}
    CDs(const std::string& Filename) :
        m_cds()
    {
        std::fstream cdfile(Filename);
        cdfile >> *this;
    }
    size_t size() { return m_cds.size(); }
    friend std::ostream& operator<<(std::ostream&, const CDs&);
    friend std::istream& operator>>(std::istream&, CDs&);
};

std::ostream& operator<<(std::ostream& os, const CDs& cds) {
    for(const CD& cd : cds.m_cds) os << cd;
    return os;
}

std::istream& operator>>(std::istream& is, CDs& cds) {
    while( !is.eof() ) {
        CD a_cd;
        is >> a_cd;
        if ( !is.eof() ) cds.m_cds.emplace_back(a_cd);
    }
    return is;
}

int main(int argc, char* argv[]) {
    std::vector<std::string> args(argv+1, argv+argc);

    CDs cds;
    for(const std::string& file : args) {
        std::fstream fs(file);
        fs >> cds;
    }
    std::cerr << "Number of CDs: " << cds.size() << "\n";
    std::cout << cds;
    return 0;
}

Я не умею использовать векторы (наш учитель страстно ненавидит векторы) и разные прототипы и структуры (заданные заданием), чем заданные ...

user10567823 30.10.2018 03:21

Учитывая эти ограничения, это можно было бы с таким же успехом превратить в чистую программу C. Интересно, почему учителю так не нравится std :: vector, но он все еще хочет, чтобы вы использовали std :: string? Они не отличаются от что.

Ted Lyngmo 30.10.2018 10:12

Подождите, учитель C++, который «страстно ненавидит векторы»? Что за ерунда?

Quentin 30.10.2018 10:47

Преподаватель "C++", который говорит вам использовать new[] вместо std::vector, учит вас не C++, а "C, который необходимо передать компилятору C++"

Caleth 30.10.2018 10:52

Другие вопросы по теме