Using a vector function on a node member - c++

I'm writing a program in C++ where I take in a line from a txt file and stick it into a vector<string> data that is within a struct (I'm making a linked list of each individual line). Technically I have a loop set up that will break up the words from the sentence I'm taking in, and pushing them into the vector one by one.
The issue I've ran into is when I try getting the vector size via
int size;
size = current->data.size();
Current being a node. I get both an implicit conversion warning and a "Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)".
Can anyone explain where I am going wrong? Is it just not possible to code something like that? Should I just create a counter variable to keep track of how many words are being placed into the vector? And what would be the best programming practice to go about achieving this?
Here is my main() file
#include <iostream>
#include <fstream>
#include "SkipGram.hpp"
using namespace std;
int main() {
string file;
ifstream inFile;
vector<string> sentence;
string line;
SkipGram control;
int skip;
int gram;
cout << "Please enter file name:\n";
cin >> file;
inFile.open(file);
while(!inFile.is_open()){ //makes sure we get a working file
cout << "Error reading in file. Please try again.";
cin >> file;
inFile.open(file);
}
cout << "Please enter how many words you want skipped and the amount of grams:";
cin >> skip >> gram;
while(!inFile.eof()){
getline(inFile, line);
control.convert(line);
}
control.skipGramFunc(skip, gram);
control.printSkipGram();
return 0;
}
Here is my .hpp file
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class SkipGram{
public:
SkipGram();
void convert(string line);
void skipGramFunc(int skip, int gram);
void printSkipGram();
private:
typedef struct sentence{
vector<string> data;
vector<string> result;
int position;
sentence* next;
}* sentencePtr;
sentencePtr first;
sentencePtr current;
int amount;
};
Here is my .cpp file
#include "SkipGram.hpp"
using namespace std;
SkipGram::SkipGram(){
first = NULL;
current = NULL;
amount = 0;
}
void SkipGram::convert(string line){
// go word by word through sentence and create a vector out of it
// add into the sentence list
sentencePtr newSentence = new struct sentence;
if(first == NULL){
current = newSentence;
first = newSentence;
amount++;
newSentence->position = amount;
}else {
current = newSentence;
amount++;
newSentence->position = amount;
}
string word;
int length = line.length();
int i = 0;
int front = 0;
int temp;
while( i <= length){
temp = line.find(" ");
if( temp == -1){
break; //catches when sentence is done with
}
word = line.substr(front, temp);
newSentence->data.push_back(word);
temp++;
line = line.erase(front, temp);
} //END OF WHILE
}
void SkipGram::skipGramFunc(int skip, int gram){
// goes through word vector and rearranges them
if(gram == 1){
cout << "Need more than one gram!" << endl;
return;
}
if(skip == 0 || gram == 0){
cout << "Input cannot be 0!";
}
int size;
int temp;
int tempAmount = amount;
current = first;
skip++;
while( tempAmount != 0){ // while loop goes through all the sentences
size = current->data.size();
size = size - skip; // size here essentially becomes a marker to find out where to stop the loop
for(int i = 0; i < size; i++){ // for loop goes through all the words
for(int j = 0; j < gram; j++){ // this loop checks to see if we got the right number of grams
if(j == 0){ // are we on the first gram
current->result.push_back(current->data.at(i));
}else { // we want skipped gram
temp = i + skip;
current->result.push_back(current->data.at(temp));
} // END OF IF
}// END OF GRAM IF
current->result.push_back(",");
}//END OF WORD FOR
current = current->next;
tempAmount--;
}//END OF WHILE
}// END OF FUNCTION
void SkipGram::printSkipGram(){
int tempAmount = amount;
current = first;
while(tempAmount != 0){
int size = current->data.size();
for(int i = 0; i <= size; i++){
cout << current->data.at(i);
};
}//END OF WHILE
}

You never assign to next, but you do read it. Whereupon your program exhibits undefined behavior by way of accessing a value of uninitialized object.

Related

accessing data within array of structure in C++

This is an assignment that required me to use ifstream to stream a CSV file. this csv file contains 52 state names and amount of different resources used by each state. for example:
Alabama,410.20,715.70,169.40,18.00,44.90,309.10,11.90,417.30,64.50,167.40,23.70,0.10,0.40,0.00
then I need to prompt the user to type the state name and the output is the percentage of resources used.
I created a struct containing a string type and an array to store the value of each state and created an array of struct to store multiple state's data, but I am not sure whether my code is right, and I want to know how to access other data, such as the data store in my double array, when the user input a state name.
here is my code:
struct statData
{
string statename;
double StatDataNumber[14];
}DataStruc[51];
int main()
{
ifstream indata;
string line;
statData State;
State.statename;
statData Consumption;
Consumption.StatDataNumber;
indata.open("Data2016.csv"); //opening file
if (indata.fail()) //fail safe
{
cout << "Fail to open file";
exit(1);
}
getline(indata, line); //skipping the first line of the csv file
int i;
int N = 0;
int NLoop;
int Loop = 0;
string InvertValueBefore;
double InvertValueAfter;
char comma;
while (indata.eof()) // before file reache the end
{
for (NLoop = 0; NLoop < 51; NLoop++) // struct array loop
{
{
getline(indata, DataStruc[Loop].statename, ',');// getting statename
for (i = 0; i <= 12; i++) // each group of data, except last
{
indata >> DataStruc[Loop].StatDataNumber[N] >> comma;// storing data in struct
N++;
}
getline(indata, InvertValueBefore); // store last value as string
InvertValueAfter = stoi(InvertValueBefore); // convert it into double
InvertValueAfter = DataStruc[Loop].StatDataNumber[N]; // store it in array of struct
}
Loop++;
}
}
ReadData();
return 0;
}
void ReadData (ifstream& indata , statData DataStruc[] )
{
int i;
string input;
bool stayinloop = true;
cout << "Enter a statename or 'q' to quit\n";
getline(cin, input);
while (stayinloop == true)
{
if (input == "Alabama")
DataStruc[i].statename == "Alabama";
DataStruc[i].StatDataNumber[]
}
}
this code is not finished. Please let me know if you spot any other error. Thank you!
Your code is fine. However, certain points:
1. You just need to get rid of certain variables which are not required.
2. The "eof" function is used to identify if the end of file is reached. For which, you need to use while (!indata.eof()).
3. The "ReadData" method should appear before the main function, however, if you want to have your functions after the main function then first you need to define your function declaration before the main function (i.e. before main function, you can put "void ReadData (ifstream& indata , statData DataStruc[]);"), afterwards you can define your function.
Below is a working version of your requirements.
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
using namespace std;
struct statData
{
string statename;
double StatDataNumber[3];
}DataStruc[2];
void ReadData (ifstream& indata , statData DataStruc[])
{
string input;
bool stayinloop = true;
while (stayinloop)
{
cout << "\nEnter a statename or 'q' to quit\n";
getline(cin, input);
for (int i = 0 ; i < 2; i++)
{
if (input == DataStruc[i].statename)
{
for(int j = 0 ; j < 3; j++)
{
cout << DataStruc[i].StatDataNumber[j] << ',';
}
}
else if(input == "q")
{
stayinloop = false;
}
}
}
}
int main()
{
ifstream indata;
string tempData = "";
string line;
string InvertValueBefore = "";
double InvertValueAfter = 0.0;
char comma = ',';
indata.open("test.csv"); //opening file
if (indata.fail()) //fail safe
{
cout << "Fail to open file";
}
getline(indata, line); //skipping the first line of the csv file
while (!indata.eof()) // before file reach the end
{
for (int NLoop = 0; NLoop < 2; NLoop++) // struct array loop
{
{
getline(indata, DataStruc[NLoop].statename, comma);// getting statename
for (int i = 0; i < 2; i++) // each group of data, except last
{
getline(indata, tempData, comma);
DataStruc[NLoop].StatDataNumber[i] = atof(tempData.c_str());
}
getline(indata, InvertValueBefore); // store last value as string
InvertValueAfter = atof(InvertValueBefore.c_str()); // convert it into double
DataStruc[NLoop].StatDataNumber[2] = InvertValueAfter;
}
}
}
ReadData(indata, DataStruc);
return 0;
}

Shifting an array of structs C++

I am quite new to c++ programming and data structures and really need some help. I am working on an assignment where I have a text file with 100 lines and on each line there is an item, a status(for sale or wanted), and a price. I need to go through the text file and add lines to an array of structs and as I add lines I need to compare the new information with the previously submitted information. If there is a line that is wanted and has a price higher than a previously input item that is for sale then the item would be removed from the struct and the array of structs shifted.
The place that I am having trouble is in actually shifting all the structs once a line that satisfies the condition is found.
My issue is that when I try to shift the array of structs using the second for loop nothing happens and I just get null structs and nothing seems to move.
Please if you guys can offer any help it would be greatly appreciated.
Below is the code of the text file and my current code.
#include<iostream>
#include<fstream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
struct items
{
string type;
int status;
int price;
} itemArray [100];
int main(int argc, char *argv[]) {
int x = -1;
//int chickenCount = 0;
int counter = 0;
int itemsSold = 0;
int itemsRemoved = 0;
int itemsForSale = 0;
int itemsWanted = 0;
string itemType;
int itemStatus = 0;
int itemPrice = 0;
int match = 0;
ifstream myReadFile( "messageBoard.txt" ) ;
std::string line;
//char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
getline(myReadFile,line); // Saves the line in STRING.
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
//cout<<line<<endl; // Prints our STRING.
x++;
std::string input = line;
std::istringstream ss(input);
std::string token;
while(std::getline(ss, token, ',')) {
counter++;
//std::cout << token << '\n';
if (counter>3){
counter =1;
}
//cout << x << endl;
if (counter == 1){
itemType = token;
//cout<< itemType<<endl;
}
if (counter == 2){
if (token == "forsale"){
itemStatus = 1;
//itemsForSale++;
}
if (token == "wanted"){
itemStatus = 0;
//itemsWanted++;
}
//cout<< itemStatus<<endl;
}
if (counter == 3){
itemPrice = atoi(token.c_str());
//cout<< itemPrice<<endl;
}
//cout<<"yo"<<endl;
}
if (x >= 0){
for (int i = 0; i<100;i++){
if (itemArray[i].type == itemType){
//cout<<itemType<<endl;
if(itemArray[i].status != itemStatus){
if (itemArray[i].status == 1){
if(itemPrice>=itemArray[i].price){
itemsSold++;
match =1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i =i-1;
break;
}
}
if (itemArray[i].status == 0){
if(itemArray[i].price>=itemPrice){
itemsSold++;
match = 1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i=i-1;
break;
}
}
}
}
}
}
if (counter == 3 && match == 0){
itemArray[(x)].type = itemType;
itemArray[(x)].status = itemStatus;
itemArray[(x)].price = itemPrice;
}
match = 0;
// cout << itemArray[x].type << " " << itemArray[x].status<<" "<<itemArray[x].price<<endl;
}
for(int i=0;i<100;i++){
cout<<itemArray[i].type<< " "<<itemArray[i].status<<" "<<itemArray[i].price<<endl;
}
//cout<<itemArray[1].price<<endl;
cout << itemsSold<<endl;
}
myReadFile.close();
return 0;
}
text file: https://drive.google.com/file/d/0B8O3izVcHJBzem0wMzA3VHoxNk0/view?usp=sharing
Thanks for the help
I see several issues in the code, but without being able to test it, I think the main problem is that you always insert new elements at position 'x' which correspond to the currently line read from the file, without taking into account any shift of elements done. You should insert the new element at the first empty slot (or just overwrite the old element instead of shifting everything).
An other issue is that you do not initialize the status and price in your array.
The best way would be to rewrite the code by using more standard C++ features, for example:
replace the items structure by a class with a constructor defining default values
use object copy (there is no need to copy a struct element by element)
use standard C++ containers like a list (see http://www.cplusplus.com/reference/list/list/) which has insert and erase methods

C++ Storing Items in Array and Setting each Token

My name is Faith and I am a beginner programmer in C++. I am working on a project where I have to read in two file and be able to separate the items in each file to its own variable. The first file has two pieces of information separated by "," and the second has three pieces of information. So far, I think I've done well with reading the files and getting each line in the file. Also I've separated each item by "," now I am trying to store those items in its on variable. Please Help! I've tried starting this project over multiple times and this is the only method I know how to implement to do this.
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h>
using namespace std;
class Manufactuer{
string upcode;
string company_name;
public:
void setupcode(string value){
upcode= value; }
void setcompany_name(string value){
company_name= value; }
string getupcode(){ return upcode;}
string getcompany_name(){return company_name;}
};
class Products{
string product_num;
string quantity;
string product_name;
public:
void setproduct_num(string value){
product_num= value; }
void setproduct_name(string value){
product_name= value; }
void setquantity(string value){
quantity = value;}
string getproduct_num(){ return product_num;}
string getquantity(){return quantity;}
string getproduct_name(){return product_name;}
};
int main(int argc, const char * argv[]) {
//opens the csv file
std::ifstream mccodesfile;
std::ifstream salesfile;
mccodesfile.open("mccodes.csv");
if(!mccodesfile){// file couldn't be opened
cout<<"Failed: file could not be opened"<<endl<<"Press Enter to Close:";
cin.get();
return 0;
}else
cout<<"Successfully opened file!"<<endl;
salesfile.open("sales.csv");
if(!salesfile){// file couldn't be opened
cout<<"Failed: file could not be opened"<<endl<<"Press Enter to Close:";
cin.get();
return 0;
}else
cout<<"Successfully opened file!"<<endl;
Manufactuer* upccodes;
int count; //how many elements in the array
int size; //how large the array
count = 0;
size = 2;
upccodes= (Manufactuer*)malloc(size*sizeof(Manufactuer)); //Malloc dynamatically reserve memory for variable pointer
string line;
while (getline(mccodesfile,line)) {// Taking every line from the file and putting in the variable line
Manufactuer newcode = Manufactuer(); //creating a upcode object
istringstream ss(line);
string token; //setting up split values
bool haveReadUPCode = false;
while (getline(ss,token,',')){// Separated values by comma
if(!haveReadUPCode){
newcode.setupcode(token);
haveReadUPCode = true;
}else{
newcode.setcompany_name(token);
}
}
if (count == size){
size = size * 2;
upccodes= (Manufactuer*)realloc(upccodes,size*sizeof(Manufactuer)); //Double the size while keeping the same elements
}
upccodes[count++]= newcode;
// cout<<line<<endl;
}
for (int i = 0; i<count; i++){
// cout<<upccodes[i].getcompany_name()<<endl; //Prints Manufactuers name--Works!
}
for (int i=0; i<count; i++) {
// cout<<upccodes[i].getupcode()<<endl; //Prints UPCcodes--Works
}
Products* product;
product= (Products*)malloc(size*sizeof(Products)); //Malloc dynamatically reserve memory for variable pointer
while(getline(salesfile, line)){{// Taking every line from the file and putting in the variable line
Products newProduct = Products(); //creating a product object
istringstream ss(line);
string token; //setting up split values
bool haveReadProduct = false;
while (getline(ss,token,',')){// Separated values by comma
if(!haveReadProduct){
newProduct.setproduct_num(token);
haveReadProduct = true;
} else{
newProduct.setproduct_name(token);
newProduct.setquantity(token);
}
}
if (count == size){
size = size * 2;
product= (Products*)realloc(product,size*sizeof(Products)); //Double the size while keeping the same elements
}
product[count++]= newProduct;
//cout<<line<<endl; //LINES ARE Printing!
}
}
for (int i = 0; i<count; i++){
// cout<<product[i].getproduct_name()<<endl; //Prints Product name--Works
}
for (int i = 0; i<count; i++){
//cout<<product[i].getproduct_num()<<endl; //Prints Product number--Works
}
}

Randomize array using pointers

Im trying to shuffle my deck of cards using pointers. My loops just print out the default value, not cycling through the cards. how do i fix this. shuffle functiuon is at the bottom? I am trying to loop through and increment pointers while replacing my destination pointer with my source pointer. or the dereferenced value. what am i doing wrong?
#include <iostream>
#include <fstream>
#include <ctime>
#include <stdlib.h>
#include <string>
using namespace std;
//global constant(s)
const int maxCards = 52;
//Structs
struct card
{
char suit[8];
char rank[6];
int cvalue;
char location;
};
struct player
{
char name[100];
int total;
};
//Function List
char * strcopy(char destination[], const char source[]);
void shuffle(card* destinationP,card* sourceP);
//program
int main()
{
//begin seeding the time for randomize later
srand(time(NULL));
//declaration of variables
bool gameOn =true;
int choice;
char tempfName[100];
char templName[100];
int count =0;
//create struct array(s)
card deck[52];
card shuffledDeck[52];
player people[4];
//create pointer and set initial value
card * deckPointer = NULL;
card * shuffledDeckPointer= NULL;
player *peoplePointer = NULL;
//
deckPointer = &deck[0]; //assign address of deck to deckPointer
shuffledDeckPointer = &shuffledDeck[0];
peoplePointer = &people[0]; //assign address of people to peoplePointer
//sets default values for the card arrays
for(int i=0;i<52;i++)
{
strcopy(shuffledDeck[i].suit, "suit");
strcopy(shuffledDeck[i].rank,"rank");
shuffledDeck[i].cvalue = 0;
strcopy(deck[i].suit,"suit");
strcopy(deck[i].rank,"rank");
deck[i].cvalue = 0;
}
//set up card file to be read in
ifstream fin;
char finName[12];
//get file name from user
cout << "Enter file name...(cardFile.txt)" << endl;;
cin >> finName;
//open the file
fin.open(finName);
//check if cardFile.txt opens correctly
if(!fin.good())
{
cout << "Error with card file" << endl;
return 0;
}
else
{
card *deckPointer = NULL;
//prime fin
//fin >> deck[i].suit;
//fin >> deck[i].rank;
//fin >> deck[i].cvalue;
while(fin.good())
{
for(deckPointer = &deck[0]; deckPointer < &deck[maxCards];deckPointer++)
{
fin >> (*deckPointer).suit;
fin >> (*deckPointer).rank;
fin >> (*deckPointer).cvalue;
}
}
}
cin.clear();
}
//Functions
//copy string function
char * strcopy(char *destination, const char* source)
{
char *p = destination;
while(*p++ = *source++);
return destination;
}
//Shuffle function
void shuffle(card *destinationP,card *sourceP)
{
int randomNumber = 0;
int count=0;
for(int j=0;j<52;j++)
{
//choose a random number up to 52
randomNumber = rand()%52;
count = 0;
if(count < randomNumber)
{
while(count < randomNumber)
{
*sourceP++;
count++;
}
//check if destination is empty ie will accept
//a card and will not overwrite a card
if((*destinationP).cvalue == 0)
{
// copy unshuffled "deck" to the shuffled "deck"
strcopy((*destinationP).suit, (*sourceP).suit);
strcopy((*destinationP).rank, (*sourceP).rank);
(*destinationP).cvalue = (*sourceP).cvalue;
*destinationP++;
}
}
else
{
if((*destinationP).cvalue == 0)
{
// copy unshuffled "deck" to the shuffled "deck"
strcopy((*destinationP).suit, (*sourceP).suit);
strcopy((*destinationP).rank, (*sourceP).rank);
(*destinationP).cvalue = (*sourceP).cvalue;
*destinationP++;
}
}}}
Just use an std::vector and std::shuffle. Also don't use rand(), use the <random> header instead. And std::string instead of char*.
I prefer the Fisher-Yeats shuffle which Donald Knuth put into his Art of Computer Programming as Algorithm P. Pseudo code can be found at: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle. Incidentally, for better randomization properties, I would recommend using a Mersenne Twister (http://en.wikipedia.org/wiki/Mersenne_Twister) for which you can find GPLd source in several languages

Read two words into one char array element

I am trying to read in two words from text file into one char array element. I CANNOT USE std::string. I get a seg fault because my loop is looping in a way that goes out of bounds. I cannot copy in the two words. please help me do this!! My loop for card struct works perfectly. I cannot get the "first last" into the people[].name
// deck of cards
// below are initializations
#include
#include
#include
#include
#include
using namespace std;
//globals
const int maxCards = 52;
//Structs
struct card {
char suit[8];
char rank[6];
int cvalue;
char location;
};
struct player {
char name[100];
int total;
card hand[4];
};
//program
int main()
{
//constants
char tempfName[100];
char templName[100];
//create struct array(s)
card deck[52];
card shuffledDeck[52];
player people[4];
//create pointers
card * deckPointer =NULL;
deckPointer = deck;
card * shuffledDeckPointer=NULL;
shuffledDeckPointer = shuffledDeck;
for(int i=0;i<4;i++)
{
strcopy(people[i].name,"first last");
}
//open player names file
ifstream fin2;
string fin2Name;
//get file name from user
cout << "Enter player file name...(Players.txt)" << endl;
getline(cin, fin2Name);
//open file
fin2.open(fin2Name.c_str());
//check if Players.txt opens correctly
if(!fin2.good())
{
cout << "Error with player file!" << endl;
return 0;
}
else
{
int j =0;
fin2 >> people[j].name; //prime file
while(fin2.good())
{
//find the length
int index =0, length=0;
while(tempfName[length] != '\0')
{
length++;
}
//now add space after first name
tempfName[length] = ' ';
length++;
while(templName[index] != '\0')
{
tempfName[length] = templName[index];
length++;
index++;
}
tempfName[length]='\0';
int counter =0;
while(templName[counter] != '\0')
{
people[0].name[counter] = templName[counter];
counter++;
}
}
}
it seems your tempfName is not pointing to a correct object in your while loop in else statement
else
{
int j =0;
fin2 >> people[j].name; //prime file
while(fin2.good())
{
//find the length
int index =0, length=0;
while(tempfName[length] != '\0')
{
length++;
}
You could do some cheating:
char full_name[256]; // Binary quantities are better.
snprintf(full_name, sizeof(full_name),
"%s %s",
first_name, last_name);
You should do more research regarding C-style string functions, like check a good reference book. It should have a chapter about the C-style string functions.
Here are some helpful ones:
strcpy, strcat, strchr, sprintf, strlen