Have problem with dynamic array of structures program - c++

Having trouble compiling program. Should read input from text file and store into a dynamic array of structure. I'm prettty sure my problem lies in the ipod_Initialize function. I'm not sure how to pass the dynamic array structure through the function.
#include <iostream>
#include <string>
#include <fstream>
# include <ctime>
using namespace std;
struct Song
{
string title;
string artist;
float size{};
};
int song_Count(string);
void ipod_Initialize(string, int, Song);
void show_playlist();
int main(char *argv[]) {
// argv is filename
int count = song_Count(argv[1]);
Song* songInfo = new Song[count];
ipod_Initialize(argv[1], count, *songInfo);
cout << songInfo[0].title;
delete[] songInfo;
return 0;
}
int song_Count(string fileName){
ifstream inFile;
string data;
int count = 0;
inFile.open(fileName);
if (!inFile.is_open()){
cout << "Error opening file" << endl;
return 0;
}
while(!inFile.eof()){
getline(inFile, data);
if (!data.empty()){
count++;
}
}
inFile.close();
count = count / 3 + 1;
return count;
}
void ipod_Initialize(string fileName, int count, Song* songInfo) {
string data;
ifstream inFile;
inFile.open(fileName);
for (int i = 0; i <= count; i++) {
getline(inFile, data);
if (!data.empty())
songInfo[i].title = data;
getline(inFile, data);
if (!data.empty())
songInfo[i].artist = data;
//getline(inFile, mem);
if (!data.empty())
inFile >> songInfo[i].size;
}
}

Related

(C++) terminate called after throwing an instance of 'std::bad_alloc'

I keep getting an error of bad memory allocation. I've spent the whole night trying to find where I went wrong but I can't figure out what.
I've combed through every line but still nothing. Could it be that my program/laptop just isn't strong enough?
Any help would be extremely helpful. My head is ringing and I need some rest.
Here's my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
// struct to store word + count combinations
struct wordItem{
string word;
int count;
};
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords);
bool isCommonWord(string word, vector<string>& _vecIgnoreWords);
void printTopN(wordItem wordItemList[], int topN);
void doubleArray(wordItem wordItemList[], int size);
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount);
const int STOPWORD_LIST_SIZE = 50;
// ./a.out 10 HW1-HungerGames_edit.txt HW1-ignoreWords.txt
int main(int argc, char* argv[]){
vector<string> vecIgnoreWords(STOPWORD_LIST_SIZE);
// verify we have the correct # of parameters, else throw error msg & return
if (argc != 4){
cout << "Usage: ";
cout << argv[0] << " <number of words> <filename.txt> <ignorefilename.txt>"<< endl;
return 0;
}
//Set vector with stop words
getStopWords(argv[3], vecIgnoreWords);
//initialize struct array
int aSize = 100;
wordItem *theStructArray = new wordItem[aSize];
int counter = 0;
int doubleCount = 0;
//read main txt file
ifstream inFile(argv[1]);
if(inFile.is_open()){
string line;
string theWord;
//extract words from file
while(getline(inFile, line)){
istringstream iss(line);
//extract and analyze word
while(iss >> theWord){
if(!(isCommonWord(theWord, vecIgnoreWords))){
bool inStructArray = false;
int inStructPosition;
//search for word in Struct array
while (inStructArray == false){
for(int i=0; i<aSize; i++){
if (theWord == theStructArray[i].word){
inStructArray = true;
inStructPosition = i;
}
}
break;
}
//if word is in struct array
if (inStructArray == true){
theStructArray[inStructPosition].count++;
}
//else if it isn't
else{
//create new wordItem and add into struct
wordItem newWord;
newWord.word = theWord;
newWord.count = 1;
theStructArray[counter+(100*doubleCount)] = newWord;
counter++;
}
//if struct array hits maximum amount of elements,
if (counter == (aSize-1)){
doubleArray(theStructArray, aSize);
counter = 0;
doubleCount++;
aSize +=100;
}
}
}
}
inFile.close();
}
//Bubble sort masterArray
int bI, bJ, flag = 1;
wordItem bTemp;
for(bI=1; (bI <= aSize && flag); bI++){
flag = 0;
for(bJ=0; bJ<aSize; bJ++){
if(theStructArray[bJ+1].count > theStructArray[bJ].count){
bTemp = theStructArray[bJ];
theStructArray[bJ] = theStructArray[bJ+1];
theStructArray[bJ+1] = bTemp;
flag = 1;
}
}
}
//Print topN words
printTopN(theStructArray, atoi(argv[1]));
//print others
cout << "#" << endl;
cout << "Array doubled: " << doubleCount << endl;
cout <<"#" << endl;
cout << "Unique non-common words: "<< (aSize-100+counter)<<endl;
cout << "#"<<endl;
cout <<"Total non-common words: "<< getTotalNumberNonCommonWords(theStructArray, aSize, counter)<<endl;
return 0;
}
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords){
ifstream inFile(ignoreWordFileName);
if(inFile.is_open()){
int a = 0;
string line;
while(getline(inFile, line)){
_vecIgnoreWords.insert(_vecIgnoreWords.begin() + a, line);
}
inFile.close();
}
return;
}
bool isCommonWord(string word, vector<string>& _vecIgnoreWords){
for(int i=0; i<STOPWORD_LIST_SIZE; i++){
if(word == _vecIgnoreWords.at(i)){
return true;
}
}
return false;
}
void printTopN(wordItem wordItemList[], int topN){
cout << endl;
for(int i=0; i<topN; i++){
cout<< wordItemList[i].count << '-' << wordItemList[i].word << endl;
}
return;
}
void doubleArray(wordItem wordItemList[], int size){
wordItem *tempArray = new wordItem[size+100];
for(int i=0; i<size; i++){
tempArray[i] = wordItemList[i];
}
delete [] wordItemList;
wordItemList = tempArray;
}
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount){
int total = 0;
for(int i=0; i<(size-100+wordCount); i++){
total+=wordItemList[i].count;
}
return total;
}
You are doing very bad things in void doubleArray(wordItem wordItemList[], int size)
you can call delete [] on the array if you pass an array, but you cannot change its value, so doubleArray(theStructArray, aSize); will cause theStructArray to be deleted but not assigned to the memory you allocated. You are just assigning the local variable in the function doubleArray
It is similar to:
void doubleit(int x)
{
x *= 2;
}
int y=3;
doubleit(y);
here x was momentarily doubled to 6, but y never changed.
you need to use references, or better make theStructArray a std::vector and be done with it.

C++ array string function

Can someone please show me how to create an array function that reads from file txt string data type
for example:
Read in the following files inside of a function:
colleges.txt
states.txt
Add the colleges/universities to a vector of strings.
Add the states to parallel arrays of strings.
Call the read function from your main function.
Thank you very much :D
Try the following code:
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
void func()
{
std::ifstream fin;
fin.open("colleges.txt", std::ifstream::in);
std::vector<std::string> vec;
std::string line;
while(getline(fin, line))
{
vec.push_back(line);
}
fin.close();
int len = vec.size();
std::string *arr = new std::string[len];
int index = 0;
fin.open("states.txt", std::ifstream::in);
while(getline(fin, line))
{
arr[index++] = line;
}
fin.close();
for(auto e:vec) std::cout<<e<<" ";
std::cout<<"\n";
for(int i = 0; i < len; ++i)
std::cout<<arr[i]<<" ";
std::cout<<"\n";
delete [] arr;
}
int main()
{
func();
return 0;
}
use vectors, Carl!
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
struct TwoVectors {
vector<string> first ;
vector<string> second;
};
TwoVectors getSomeData() {
TwoVectors ret;
auto collegesReader = ifstream("colleges.txt");
auto statesReader = ifstream("states.txt");
string temp;
while (getline(collegesReader, temp))
ret.first.push_back(temp);
while (getline(statesReader, temp))
ret.second.push_back(temp);
collegesReader.close();
statesReader.close();
return ret;
}
int main() {
auto someData = getSomeData();
for (auto something : someData.first)
cout << something << endl;
for (auto something : someData.second)
cout << something << endl;
return 0;
}

Program crashes due to undefined behavior

So I'm writing a program that creates a library for a collection of CDs and displays them. My program compiles but crashes whenever I write an array of pointers to songs from a file into structs contained within an array shown here:
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
I think it's due to undefined behavior, here's the .cpp file that this is happening in.
#include <iostream>
#include "CDs.h"
#include "CD.h"
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
//Creates a collection of CDs
CDs* createCDs(const char* file_name)
{
//Declare variables and allocate memory
int max_cds = 50;
CDs* collection = new CDs;
collection->max_cds = max_cds;
CD** cd_array = new CD*[max_cds];
int num;
int sentinel = 0;
String* word;
string line;
CD* cd;
const char* sub;
String* length;
String* title;
//Open .txt file
ifstream infile;
infile.open(file_name);
if (infile.is_open())
{
while (infile.good())
{
for (int i = 0; i < max_cds; i++)
{
//Get the artist from .txt file
cd = cd_array[i];
getline (infile, line);
sub = line.c_str();
word = createString(sub); //Create string from infile line
cd->artist = word;
destroyString(word);
//Get the Title of the album from file
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cd->title = word;
destroyString(word);
//Get the Year of the album from file
infile >> num;
cd->year = num;
//Get the Rating
infile >> num;
cd->rating = num;
//Get number of tracks
int num_songs;
infile >> cd->num_tracks;
//Get song array
for (int a = 0; a < num_songs; a++)
{
getline (infile, line);
sub = line.c_str();
word = createString(sub);
cout << "SHIT" << endl;
length = substr(word, -1, 5);
title = substr(word, 5, strlen(sub));
cd->song_array[a] = createSong(title,length);
destroyString(word);
}
cd_array[i] = cd;
sentinel++;
}
}
}
else
{
cout << "file did not open";
}
collection->cd_array = cd_array;
collection->num_cds = sentinel;
collection->max_cds = max_cds;
return collection;
}
I have no idea what to do to make this run, If someone could help that would be amazing.
edit - I didn't give the .cpp that is included and has some of the functions used
#include <iostream>
#include <cstring>
#include "String.h"
using namespace std;
//Function that creates a string
String* createString(const char* char_array)
{
//Allocate memory for a pointer to String struct
//String* string;
String* string = new String;
//Write the char_array to String struct
int length = strlen(char_array);
char array[30];
for (int i = 0; i <= length; i++)
{
array[i] = char_array[i];
string->array[i] = array[i];
}
return string;
}
//Function that displays the string
void displayString(String* str)
{
for (int i = 0; i < strlen(str->array); i++)
{
cout << str->array[i];
}
cout << endl;
}
//Function that destroys the string
void destroyString(String* str)
{
delete str;
str = NULL;
}
int find(String* str, char delimiter, int start)
{
for (int i = start; i <= strlen(str->array); i++)
{
if (str->array[i] == delimiter)
{
return i;
}
}
cout << "No occurences of delimiter were found" << endl;
return -1;
}
String* substr(String* str, int start, int end)
{
String* new_str = new String;
int count = 0;
for (int i = start + 1; i < end - 1; i++)
{
new_str->array[count] = str->array[i];
count++;
}
return new_str;
}
void compare(String* str1, String* str2)
{
if (str1->array < str2->array)
{
cout << str1->array << " is less than " << str2->array << endl;
}
if (str1 > str2)
{
cout << str2->array <<" is less than " << str1->array << endl;
}
if (str1 == str2)
{
cout << "The strings are equal" << endl;
}
}
You never allocate memory for the effective CD. You just allocate an array of pointers to CDs (cd_array). This means you have an array of pointers, pointing to unkown memory locations.
The best way to ensure no such bad access is possible, is to not dynamically allocate memory. Just use CD cd_array[max_cds] and work with that. (Use call by reference, if you need to pass this to a function.)
You need to add the following lines:
//Get the artist from .txt file
cd_array[i] = new CD;
cd = cd_array[i];
.....
You should de-allocate the memory once finished using them
for(...)
delete cd_array[i];
delete []cd_array;

Reading from file C++

I need to read this txt file but I don't understand what I'm doing wrong?
http://pastebin.com/gPVbuvhb Here's my reading function
void Read(School & snew){
string school, name, group;
Student S;
ifstream fd(CD);
getline(fd, school, ';');
S.SetSchool(school);
cout << S.GetSchool() << endl;
while(!fd.eof()){
getline(fd, name, ',');
fd >> ws;
getline(fd, group, ' ');
int Paz[Student::M];
int kiek = 0;
while(fd.peek()!= '\n' && !fd.eof()){
fd >> Paz[kiek++];
}
fd.ignore();
}
fd.close();
}
Here's my Student class
class Student{
public:
static const int M = 5;
private:
string school, name, group;
int *Marks; // dynamic array of student marks
int nmax; // max size of array
int n; // current size of array
void IncreaseCapasity(int kiek);
public:
Student(int nmax = 0);
~Student();
void SetMarks(int mark);
void SetSchool(string school);
void SetName(string name);
void SetGroup(string group);
int GetMark(int i){return Marks[i];}
string GetSchool(){return school;}
string GetName(){return name;}
string GetGroup(){return group;}
int GetN(){return n;}
};
Student::Student(int nmax):Marks(NULL), n(n), nmax(nmax){
if(nmax > 0){
Marks = new int[nmax];
}
}
Student::~Student(){
if(Marks){
delete [] Marks;
Marks = NULL;
}
}
void Student::IncreaseCapasity(int kiek){ // maybe this function is incorrect?
if(kiek > nmax){ // if array increasing
int *SNew = new int [kiek];
for(int i=0; i<n; i++)
SNew[i] = Marks[i];
delete [] Marks;
Marks = SNew;
nmax = kiek;
}if(kiek < nmax){ // if array decreasing
int *SNew = new int [kiek];
for(int i=0; i<kiek; i++)
SNew[i] = Marks[i];
delete [] Marks;
Marks = SNew;
n = nmax = kiek;
}
}
void Student::SetMarks(int mark){
if(n == nmax) IncreaseCapasity(n + M);
Marks[n] = mark;
n++;
}
void Student::SetSchool(string school){
this->school = school;
}
void Student::SetName(string name){
this->name = name;
}
void Student::SetGroup(string group){
this->group = group;
}
when I'm reading int values fd >> Paz[kiek++]; I get this error
Unhandled exception at 0x571121F8 (msvcp110d.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x0000000D.
getline(fd, school, ';');
reads from the fd stream, stopping at first occurence of ';'. Since there is no ';' in your file, it reads whole file into school string.
What you actually want to do is to parse your file line by line, constructing instance of istringstream using each line:
std::string line;
while (std::getline(fd, line)) {
if (line.empty())
continue;
std::istringstream is(line);
std::string name, group;
if (std::getline(is, name, ',') && std::getline(is, group, ',')) {
std::cout << "Name: " << name << " Group: " << group << std::endl;
}
}
just don't forget to #include <sstream>.
Also note that:
while (!fd.eof()) {
std::getline(...);
// relying on getline call being successful here
}
is not safe, just use its return value directly.

Problem with reading from csv file after writing to it in C++

I'm quite new to C++, I'm trying to achieve a task whereby i could read from a csv file and write to that same file and vice versa depending on the user's selection. This is what i did:
Here's the data already on file
1,Mickey,23,090,Girne,TRNC,465
2,Charles,23,090,Girne,TRNC,465
3,Species,23,090,Girne,TRNC,465
4,Moody,23,090,Girne,TRNC,465
5,Kpokiyo,23,090,Girne,TRNC,465
6,Sualp,23,090,Girne,TRNC,465
Here's the code i wrote so far
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
bool checkIsFile();
void addUser(string e[][7], int num);
void readAllUsers(string x[][7]);
void breakArray(string x[], string y[][7], int num);
bool checkAccout(string x[], int y, string search);
void findUser(string x[], string y[],string z[], string a[],string t[],
string c[], string d[]);
int findRowNumber();
int main()
{
int option;
int acc;
string emp[findRowNumber()][7];
string account[findRowNumber()], age[findRowNumber()],name[findRowNumber()],
state[findRowNumber()], city[findRowNumber()], phone[findRowNumber()],
zip[findRowNumber()];
//infinite loop
while(true){
cout<<"-------------------------\n";
cout<<"Menu Options\n";
cout<<"1 Add account\n";
cout<<"2 List Accounts\n";
cout<<"3 Delete account\n";
cout<<"4 Find user\n";
cout<<"5 Exit program\n";
cout<<"-------------------------\n";
cin>>option;
if(option==1)
{
readAllUsers(emp);
addUser(emp, findRowNumber());
}
else if(option==2)
{
readAllUsers(emp);
}
else if(option==3)
{
//delete a user;
}
else if(option==4)
{
//find user
readAllUsers(emp);
breakArray(account,emp,0);
breakArray(name,emp,1);
breakArray(age,emp,2);
breakArray(phone,emp,3);
breakArray(city,emp,4);
breakArray(state,emp,5);
breakArray(zip,emp,6);
findUser(account,name,age,phone,city,state,zip);
}
else if(option==5)
{
return 0;
}
else
{
cout<<"Invalid option\n";
}
}
}
void addUser(string e[][7], int num)
{
string emp[num + 1][7];
for(int a=0;a<num;a++)
{
for(int b=0;b<7;b++)
{
emp[a][b] = e[a][b];
}
}
//just to test if it works
emp[num][0] = "10";
emp[num][1] = "10";
emp[num][2] = "10";
emp[num][3] = "10";
emp[num][4] = "10";
emp[num][5] = "10";
emp[num][6] = "10";
ofstream inFile;
inFile.open("info.csv");
for(int a=0;a<num + 1;a++)
{
for(int b=0;b<7;b++)
{
cout<<emp[a][b];
}
}
for(int i=0;i<num +1; i++)
{
inFile << emp[i][0] + "," + emp[i][1] + "," + emp[i][2] + "," + emp[i][3] + "," + emp[i][4] + "," + emp[i][5] + "," + emp[i][6]<<endl;
}
inFile.close();
}
void readAllUsers(string x[][7])
{
ifstream inFile("info.csv");
string line;
int linenum = 0;
while (getline (inFile, line))
{
istringstream linestream(line);
string item;
int itemnum = 0;
while (getline (linestream, item, ','))
{
x[linenum][itemnum] = item;
itemnum++;
}
linenum++;
}
inFile.close();
}
void breakArray(string x[], string y[][7], int num)
{
for(int i=0;i<findRowNumber();i++)
{
for(int j=0;j<7;j++)
{
x[i] = y[i][num];
}
}
}
bool checkAccout(string x[], int y, string search)
{
bool check = false;
for(int i=0;i<y;i++)
{
if(x[i]==search)
{
check = true;
}
}
return check;
}
void findUser(string x[], string y[],string z[], string a[],
string t[], string c[], string d[])
{
string search;
bool check = false;
cout<<"Enter Account Number to Search: ";
cin>>search;
for(int i=0;i<findRowNumber();i++)
{
if(x[i]==search)
{
cout<<"Account Number: " + x[i]<<endl<<
"Name:\t\t" + y[i]<<endl<<
"Age:\t\t" + z[i]<<endl<<
"Phone:\t\t" + a[i]<<endl<<
"City:\t\t" + t[i]<<endl<<
"State:\t\t" + c[i]<<endl<<
"Zip:\t\t" + d[i]<<endl;
check = true;
}
}
if(!check)
cout<<"User does not exist"<<endl;
}
int findRowNumber()
{
ifstream inFile("info.csv");
string line;
int linenum = 0;
while (getline (inFile, line))
{
linenum++;
}
inFile.close();
return linenum;
}
It seems to work great when i choose to search for a user(selecting 4). However, the problem is when i try to write to file, it's works but when i try to do any other task like searching the user again or re-writing to file, the program crashes.
Please what i'm i doing wrong.
Thanks
Your emp string array in the main function is declared with the initial size of the file and never resized when you add more entries, hence the crash when it tries to read a bigger file into the old size of array.