Shifting an array of structs C++ - 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

Related

I'm getting this warning sign Array index 4001 is past the end of the array (which contains 4001 elements)

I have two questions
First: When i try to run the code it gives me a warning where it says "Array index 4001 is past the end of the array (which contains 4001 elements)"
Second: I want to read the words from the file and then pass them through the function so i can
add the words to the hash table and index them accordingly and print the count of the unique words from the text file. the size function does that. can someone please help me with this
#include <iostream>
#include <string>
#include <fstream>
#define HASHSIZE 4001
using namespace std;
class entry {
public:
string word;
int frequency;
entry() { frequency = 0; }
};
class Hashtable {
private:
entry entryArr[HASHSIZE];
int updateArr[HASHSIZE];
int costArr[HASHSIZE];
int sizeUnique = 0;
int probeCount;
int updateCount;
public:
int HashKey(string key)
{
int totalsum = 0;
// this function is to assign every word a key value to be stored against.
for (int i = 0; i < key.length(); i++) totalsum += int(key[i]);
return (totalsum % HASHSIZE);
}
void update(string key) {
int k = HashKey(key);
if (entryArr[k].frequency == 0) {
entryArr[k].frequency++;
updateCount++;
probeCount++;
sizeUnique++;
}
// function to enter the unique words in the array
else if (entryArr[k].word == key) {
entryArr[k].frequency++;
probeCount++;
}
while (entryArr[k].frequency != 0 && entryArr[k].word != key) {
k++;
}
if (entryArr[k].word == key) {
entryArr[k].frequency++;
} else {
entryArr[k].word = key;
}
sizeUnique++;
updateCount++;
probeCount++;
}
int probes() {
costArr[HASHSIZE] = probeCount;
return probeCount;
}
int size() // function to count the total number of unique words occuring
{
int count = 0;
updateArr[HASHSIZE] = updateCount;
for (int i = 0; i < HASHSIZE; i++)
if (updateArr[HASHSIZE] != 0) {
count = costArr[i] / updateArr[i];
}
cout << count;
return count;
}
};
int main() {
entry e;
Hashtable h;
ifstream thisfile("RomeoAndJuliet.txt");
if (thisfile.is_open()) {
while (!thisfile.eof) {
h.update(e.word);
}
thisfile.close();
cout << "The total number of unique words are: " << h.size();
}
return 0;
}
An array with 4001 elements has valid indexes 0,1,...,3999,4000 as C++ is indexing from 0.
When i try to run the code it gives me a warning where it says "Array index 4001 is past the end of the array (which contains 4001 elements)"
This is because array index starts with 0 instead of 1. And so an array of size 4001 can be safely indexed(accessed) upto 4000 and not 4001.
I want to read the words from the file and then pass them through the function so i can add the words to the hash table and index them accordingly and print the count of the unique words from the text file
The below program shows how to do this. The program shown below counts how many times a given word occurred in a given input.txt file and then print that count infront of the word.
#include <iostream>
#include <map>
#include <sstream>
#include<fstream>
int main() {
std::string line, word;
//this map maps the std::string to their respective count
std::map<std::string, int> wordCount;
std::ifstream inFile("input.txt");
if(inFile)
{
while(getline(inFile, line, '\n'))
{
std::istringstream ss(line);
while(ss >> word)
{
//std::cout<<"word:"<<word<<std::endl;
wordCount[word]++;
}
}
}
else
{
std::cout<<"file cannot be opened"<<std::endl;
}
inFile.close();
std::cout<<"Total unique words are: "<<wordCount.size()<<std::endl;
for(std::pair<std::string, int> pairElement: wordCount)
{
std::cout << pairElement.first <<"-" << pairElement.second<<std::endl;
}
return 0;
}
The output of this program can be seen here.
Note that(as shown in above example) there is no need to create a separate class for the purpose given in your second question. We can do this(as shown above) literally using 4 to 6 lines(excluding opening and closing the file) of code.

Logic for the string to not fall in the middle of another string

I need help in figuring out the logic or code to when I want my string not to fall in the middle of another string. For example my given word is "Birthday!" and the other string to look for it is "Happy Birthday Scott". It's going to return a false value because it's missing an exclamation point. Here is the code that I've worked
int Words::matchWords(const char* string, const char* sentence, int wordNum){
int wordCount = words(sentence); // the words function counts the number of words in the sentence
int strLength = strlen(str);
int sentLength = strlen(sentence);
int i = 0;
char strTemp[100];
char sentenceTemp[100];
strcpy(strTemp, str);
strcpy(sentenceTemp, sentence);
if (wordNum > wordCount) {
return false;
}
char* temp;
for (i = 0; i < strLength; i++) {
strTemp[i] = tolower(str[i]);
}
for (i = 0; i < sentLength; i++) {
sentenceTemp[i] = tolower(str[i]);
}
temp = strstr(sentenceTemp, strTemp);
if (temp != NULL) {
return true;
if (strTemp[i] != sentenceTemp[i]) {
return false;
}
else
return true;
}
else
return false;
}
Here is a super simple program for you to look at.
All you have to do for this problem is create your strings using std::string, determine if they are inside the big string using find(), and lastly check if it was found using string::npos.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string bday = "Birthday!";
string str1 = "Happy Birthday Scott";
int found1 = str1.find(bday);
string str2 = "Scott, Happy Birthday!";
int found2 = str2.find(bday);
if (found1 == string::npos) //if Birthday! is NOT found!
{
cout << "str1: " << "FALSE!" << endl;
}
if (found2 != string::npos) //if Birthday! IS found!
{
cout << "str2: " << "TRUE!" << endl;
}
}
Note that for string::npos, you use == for something NOT being found and != for something that IS found.

I need to write a c++ program with these objectives

A C++ program which read data from a text file. Suppose text file contains a
paragraph about any topic. Your program asks user to enter file name without extension. Now, a
user defined function (name: ReadWordByWord()) reads all data word by word and store in a
character type array with dynamically grows according to the data.
Finally, declare a user-defined function (name: SaveInReverse()) which stores this text into a
text file (name is entered by user) in reverse order of words e.g. last words will be stored at start,
then 2nd last word, 3rd last word etc. of the original document.
And here is what I've done so far... Here I am not using the delete command, that if I use will cause an error- a heap error. How can I accomplish that first? And then what are any tips to improve this program.
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
char* readWordByWord(char * old)
{
int coun = 0;
for (int i = 0; old[i] != '\0'; i++) // to find the length of word
{
coun++;
}
char *newArr = new char[coun + 1];
strcpy(newArr, old);
//delete[]old; // this is where i am putting delete command to delete the previous i.e old array and then return the new one
return newArr;
}
int size = 100;
int main()
{
fstream fin;
string forCopy[1000];
int index = 0;
fin.open("file.txt");
char *p = new char[size];
while (fin >> p)
{
p = readWordByWord(p);
//cout << p<<endl;
forCopy[index++] = p;
/*for (int i = 0; p[i] != '\0'; i++)
{
}*/
}
for (int i = index - 1; i > 0; i--)
cout << forCopy[i] << " ";
delete[]p;
p = NULL;
fin.close();
return 0;
}
I've made it from start again (must not include newlines since only a paragraph required):
#include <iostream>
#include <fstream>
#include <string>
void reverse(char *begin, char *end) { // reverses a word
char temp;
while (begin < end) {
temp = *begin;
*begin++ = *end;
*end-- = temp;
}
}
void reverseParagraph(char *arg) { // reverses each word of the paragraph
char *word_begin = arg;
char *temp = arg;
while (*temp) {
temp++;
if (*temp == '\0')
reverse(word_begin, temp - 1);
else if (*temp == ' ') {
reverse(word_begin, temp - 1);
word_begin = temp + 1;
}
}
reverse(arg, temp - 1);
}
int main() {
std::ifstream file("file.txt");
std::string fileData = "";
while(getline(file, fileData)); // counting the number of letters for memory allocation
size_t len = fileData.length();
char *str = new char[len + 1];
strcpy(str, fileData.c_str());
reverseParagraph(str); // reverse the entire character pointer
std::cout << str << std::endl; // displays for testing
std::ofstream fileOut("out.txt");
fileOut << str << std::endl; // saving the output into another file
fileOut.close();
delete[] str;
file.close();
return 0;
}
This program firstly gets the containing data of a file and then assigns into a variable. The variable is then converted into character (pointer) after getting the string length.
After that, it recursively reverses the position each word of the fileData and finally it displays. The modified data is thereafter printed into another file.

Using a vector function on a node member

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.

Returning string from a function causing formatting issues

It's supposed to look like this: http://i.imgur.com/gko501E.png
Instead it looks like this: http://i.imgur.com/ISwqyD8.png
When I take the code out of the function and use it in the main class it works properly. However once I put it in this function the formatting problems occur, it also isn't filtering like it's supposed to. This program is supposed to take user input, store it in a string, remove all non-alphabetical characters, capitalize the vowels, and then space it out based on user defined variables given in the command line. It's also supposed to accept files as input in the command line, such as: 'program 5 8 < file'.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
using namespace std;
//make vowels uppercase
string filter(string input)
{
size_t found = input.find_first_of("aeiou");
while (found != string::npos)
{
if (islower(input[found]))
{
input[found] = toupper(input[found]);
found = input.find_first_of("aeiou", found + 1);
}
}
//Make consonants lowercase
size_t foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ");
while (foundLower != string::npos)
{
if (isupper(input[foundLower]))
{
input[foundLower] = tolower(input[foundLower]);
foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ", foundLower + 1);
}
}
//remove punctuation
for (int i = 0, len = input.size(); i < len; i++)
{
if (!isalnum(input[i]))
{
input.erase(i--, 1);
len = input.size();
}
}
return input;
}
int main(int argc, char* argv[])
{
int wordSize;
int wordSizeCounter;
int wordCounter = 0;
int rowSize;
//char letter;
wordSize = atoi(argv[1]);
rowSize = atoi(argv[2]);
ifstream inFile;
inFile.open(argv[3]);//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
string test = strStream.str();//str holds the content of the file
if (!inFile) test = cin.get() ; // Read first character
//Begin filter for files
while (!test.empty())
{
filter(test);
if (test.length() < wordSize) //make sure we don't go out-of-bounds
{
wordSize = test.length();
}
cout << test.substr(0, wordSize);
cout << " ";
if (test.length() >= wordSize) //again, make sure we don't go out-of-bounds
{
test = test.substr(wordSize);
}
else
{
test = " ";
}
wordCounter++;
if (wordCounter == rowSize)
{
cout << std::endl;
wordCounter = 0;
}
if(test.empty())
{
test = cin.get();
}
}
cout << endl;
return 0;
}