Итак, у меня есть три 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)
Я попытался отследить свой код на предмет висящих указателей, я убедился, что я «обновил» все разделы памяти, которые возвращаю ... и т. д. И т. Д.
Есть ли требование не использовать подходящий контейнер? Пара std::vector
поверх другого предложения использовать объекты вместо указателей значительно упростит это. Это также предотвратит утечку памяти, когда возникнет исключение после того, как вы в противном случае что-то сделали бы new
.
«Я удостоверился, что я« обновил »все разделы памяти, которые возвращаю… и т. д.» Я немного озадачен, почему вы думаете, что «новое» все хорошо. Вы должны сделать наоборот: убедитесь, что у вас нет ничего new
.
Добро пожаловать в Stack Overflow. Когда вы пишете код, неплохо было бы начать с чего-то небольшого и простого, которое отлично работает, а затем постепенно наращивать его. Здесь вы написали сразу много кода, и он не работает. И вы не дали нам достаточно, чтобы воспроизвести ошибку, даже если мы обнаружим ошибки некоторые, мы не можем быть уверены, что нашли все из них.
Вы удаляете вещи внутри циклов for
, к которым вы все еще обращаетесь на следующей итерации.
Очевидно, ваш delete
не соответствует вашему new
. Вы делаете один new[]
и несколько delete[]
. Кроме того, вы никогда не выделяете память для указателей внутри вашего массива. При удалении вы удаляете весь массив несколько раз (а не каждый элемент, за которым следует массив). Мне кажется, что у вас много бесполезных переменных. Вы не загадываете с памятью и надеетесь, что она сработает. Если это не домашнее задание для изучения распределения памяти и указателей на указатели, лучше вместо этого использовать дизайн, основанный на STL.
Я бы держался подальше от 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;
}
Я не умею использовать векторы (наш учитель страстно ненавидит векторы) и разные прототипы и структуры (заданные заданием), чем заданные ...
Учитывая эти ограничения, это можно было бы с таким же успехом превратить в чистую программу C. Интересно, почему учителю так не нравится std :: vector, но он все еще хочет, чтобы вы использовали std :: string? Они не отличаются от что.
Подождите, учитель C++, который «страстно ненавидит векторы»? Что за ерунда?
Преподаватель "C++", который говорит вам использовать new[]
вместо std::vector
, учит вас не C++, а "C, который необходимо передать компилятору C++"
Зачем тебе все
new
? Просто вернитесь по значению, а не по указателю.