for part of a school lab I need to read in unique words and their corresponding count with a struct. I am new to structs so please bear with me. I am getting an access violation when I try to write the adress of the current word to the character pointer inside of the current instance of my struct. I have read that this is due to dereferencing a nullptr. I have tried to understand this, but I just don't get it. I have resized arrays just like this on regular char** arrays for accepting new words. I am at a loss, any help would be greatly appreciated. The input file used here is just random words separated by non letter characters but not - or , Here is my code:
#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
using std::cin;
using std::cout;
using std::endl;
using std::setw;
using std::right;
using std::left;
using std::ifstream;
using std::ofstream;
const int BUFFER = 100; //I figure this buffer is big enough for any given word
struct Word_Count_STRUCT
{
char* WORD = nullptr;
int COUNT = 0;
};
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//Input for phrase
ifstream iphrase;
//Output to CSV (word count)
ofstream o_count;
//Word Exceptions
ifstream xinWord;
char wordbuffer[BUFFER] = { '\0' };
char ch = 0;
Word_Count_STRUCT** uniquewords = nullptr;
Word_Count_STRUCT** temp = nullptr;
int k = 0;
int wordcount = 0;
char* cword = nullptr; //Current Word
bool NextWord_flag = false;
bool interwordpunct = false;
bool NewWord_flag = true;
iphrase.open("C:\\Users\\me\\Desktop\\henroE.txt");
if (iphrase.is_open())
{
while (!iphrase.eof())
{
iphrase.get(ch);
if (isalpha(ch) || ch == '\'' || ch == '-')
{
wordbuffer[k] = ch;
++k;
NextWord_flag = true;
if (ch == '\'' || ch == '-')
interwordpunct = true;
}
if ( (NextWord_flag == true) && (!isalpha(ch)) && (interwordpunct == false) )
{
k = 0;
cword = new char[strlen(wordbuffer) + 1];
strcpy(cword, wordbuffer);
memset(wordbuffer, '\0', sizeof(wordbuffer));
for (int i = 0; (i < wordcount) && (NewWord_flag == true); ++i)
{
int cmp = _stricmp(uniquewords[i]->WORD, cword);
if (cmp == 0)
{
NewWord_flag = false;
uniquewords[i]->COUNT++;
delete[] cword;
}
}
if (NewWord_flag == true)
{
temp = new Word_Count_STRUCT * [wordcount + 1]();
for (int i = 0; i < wordcount; ++i)
{
temp[i] = uniquewords[i];
}
delete[] uniquewords;
temp[wordcount]->WORD = cword;
temp[wordcount]->COUNT++;
uniquewords = temp;
++wordcount;
NextWord_flag = false;
}
interwordpunct = false;
NewWord_flag = true;
}
}
}
I get an error on this line:
temp[wordcount]->WORD = cword;
I also get an error on the int value COUNT as well if I comment the line above it out. So I am guessing it is something with how I initialized the struct.
Worth noting that if I do not initialize this call:
temp = new Word_Count_STRUCT * [wordcount + 1]();
and instead just leave it as
temp = new Word_Count_STRUCT * [wordcount + 1];
I get another access violation but for reading instead of writing at 0xFFFFF...
At a loss, thank you for any help :)
You've got a number of things wrong. First, using fixed-length character buffers instead of C++ strings is about 20 years out of date and WILL cause buffer overflow errors unless you are exceedingly careful.
But this is an issue:
temp = new Word_Count_STRUCT * [wordcount + 1]();
for (int i = 0; i < wordcount; ++i)
{
temp[i] = uniquewords[i];
}
delete[] uniquewords;
But where did you allocate uniquewords? You declared it.
You also allocate cword outside a loop but the delete it inside a loop -- which seems really fishy, too.
But note that all you've allocated are pointers. I don't see you actually allocating the structure you're trying to put data in.
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.
After some criticism regarding this post I have decided to try another solution to test my issue.
I purpose of the code below was to save user input into an array and then output it when user types in exit. I am relatively new to C++ which means that I am aware that this is a code issue.
The constraints for this code are to not use STL or strings.
I have attached the code below which does not give the desired output, instead it prints out "exit" the number of times equal to the number of items stored in the array.
#include <iostream>
char * textArr[1000];
int lineCount = 0;
void saveText(char * text) {
textArr[lineCount] = new char(1000);
strcpy(textArr[lineCount], text);
}
int main()
{
char * line = new char(1000);
while (lineCount < 1000) {
std::cin.getline(line , 1000);
if (strcmp(line, "exit") == 0) {
break;
}
saveText(line);
lineCount++;
}
for (int i = 0; i < lineCount; i++) {
std::cout << textArr[i] << std::endl;
}
delete(textArr);
delete(line);
return 0;
}
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
#include "mbed.h"
#include "C12832_lcd.h"
#include<cstring>
#include<string>
#include<sstream>
C12832_LCD lcd;//creating LCD object
Serial s_comms(USBTX, USBRX);//creating a serial comms object
DigitalIn Button(p14);//using button to change pages
int main()
{
char str[100] = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
char*point;
point = strtok(str, ",");
int page_state = 0;
for (int i = 0; point != NULL; i++){
//time
if (i == 1 and page_state == 0){
//using substrings to extract time elements
string time = point;
string hrs = time.substr(0, 2);
string mins = time.substr(2, 2);
string sec = time.substr(4, 2);
//using string streams to reformat time string
ostringstream tim;
tim << hrs << ":" << mins << ":" << sec;
time = tim.str();
lcd.cls();
lcd.locate(0, 1);
lcd.printf("%s\n", time.c_str());
}
//date
if (i == 9 and page_state == 0){
string date = point;
string day = date.substr(0, 2);
string month = date.substr(2, 2);
string year = date.substr(4, 2);
//Converting the numerical month into abbreviation ect.
if (month == "03"){
month = "Mar";
}
if (month == "04"){
month = "Apr";
}
ostringstream dat;
dat << day << "-" << month << "-20" << year;
date = dat.str();
lcd.locate(0, 9);
lcd.printf("%s\n", date.c_str());
}
//latitude
if (i == 3 and page_state == 0){
string lati = point;
string lati_deg = lati.substr(0, 2);
string sml_latideg = lati.substr(2, 6);
ostringstream lat;
lat << "Lat: " << lati_deg << " deg " << sml_latideg << "'";
lati = lat.str();
lcd.locate(0, 18);
lcd.printf("%s", lati.c_str());
}
//latitude direction (N or S)
if (i == 4 and page_state == 0){
string lat_dir = point;
lcd.printf("%s\n", lat_dir.c_str());
}
point = strtok(NULL, ",");
}
//Change page
if (Button == 1){
page_state = !page_state;//toggle page state
wait(0.2);//debounce timer
lcd.cls();
}
//second page
for (int j = 0; point != NULL; j++){
char str[100] ="$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
char*point;
point = strtok(str, ",");
//longitude
if (j == 5 and page_state == 1){
string lngi = point;
string lngi_deg = lngi.substr(0, 2);
string sml_lngideg = lngi.substr(2, 6);
ostringstream lng;
lng << "Lng: " << lngi_deg << " deg " << sml_lngideg << "'";
lngi = lng.str();
lcd.locate(0, 1);
lcd.printf("%s", lngi.c_str());
}
//longitude direction (E or W)
if (j == 6 and page_state == 1){
string lng_dir = point;
lcd.printf("%s\n", lng_dir.c_str());
}
//speed
if (j == 7 and page_state == 1){
string speed = point;
ostringstream spd;
spd << "Speed: " << speed;
speed = spd.str();
lcd.locate(0, 9);
lcd.printf("%s\n", speed.c_str());
}
point = strtok(NULL, ",");
}
return 0;
}
hello, trying to get the onboard button on an mbed application board to allow me to clear the screen and put new info, the button currently does nothing, i am getting the first 4 parts of info on the screen however this does not change when the button is pressed, i need help to try to make this work
This does not directly answer OP's question, but this should be more helpful in the long run. Rather than trying to debug the program logic in a limited environment it is often helpful to replace the platform-specific functionality with functions and classes that allow simulation of of the platform on general purpose computing hardware without having to change the code.
By adding
#include <cstdarg>
#include <iostream>
and a fake C12832_lcd.h
#pragma once
#include <cstdarg>
#include <iostream>
// Sim LCD class. Just writes LCD commands to console
class C12832_LCD
{
public:
void cls()
{
std::cout << "LCD: Cleared" << std::endl;
}
void locate(int row, int col)
{
std::cout << "LCD: positioned " << row << "," << col << std::endl;
}
void printf(const char * fmt, ...)
{
char buffer[4096];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
std::cout << buffer << std::endl;
va_end(args);
}
};
And a bogus mbed.h
#pragma once
// Sim DigitalIn class. Toggles true and false on the button. First call will be true
class DigitalIn
{
private:
bool mVal;
public:
DigitalIn(int): mVal(false)
{
}
bool operator==(int)
{
mVal = !mVal;
return mVal;
}
};
//Sim serial Does nothing yet.
class Serial
{
public:
Serial(int, int)
{
}
};
//sim wait. We don't need to wait in simulation, so does nothing.
void wait(double)
{
}
const int p14 = 14;
const int USBTX = 0;
const int USBRX = 0;
to OP's code, I can now compile and run on the desktop in the Visual Studio IDE and throw the awesome might of the debugger at the problem. Stepping through the code quickly reveals the first of two logic errors. The second one is a bit more subtle. Watch your scope.
A quick recommendation:
Rather than using strtok, consider using the std::getline overload that takes a character delimiter. This allows
std::stringstream stream(str);
std::string token;
while (std::getline(stream, token, ','))
{
// do stuff
}
to read through a comma separated stream of input like a NMEA string.