Troubles trying to convert string to char[][] - c++

I'm building a class named Board, that will get it's details from a txt file.
#define ROW 25;
#define COL 80;
class Board
{
char _board[ROW][COL] = {0};
public:
Board(string name); // our new constructor - reads map from file.
};
It receives string name, and tries to open a file with the specific name.
In case we are indeed in the right file, I want to read the chars from it, and copy them into a board.
I've been trying several things, that are summed up in this code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
Board::Board(string name)
{
string line;
ifstream file(name);
int i = 0;
if (file.is_open())
{
while (!file.eof())
{
(1) getline(file, line);
(2) const char* test = line.c_str();
(3) strcpy_s(_board[i], test);
(4) _board[i] = line;
i++;
}
// MORE FUNCTIONS NOT RELEVANT TO THIS QUESTION
}
}
I get the following errors:
For (3): The program crashes.
For (4): expression must be a modifiable lvalue.
For (1), (2): test and line are worked well.
Is there any other simplier way to copy string to char* without using ugly loops, and copy every single char?
Why is (3) crashing my program?
Thanks in advance!

Unrelated, but void main() had been deprecated for ages and is incorrect in current versions of the standard: it shall be int main()...
Next while (!file.eof()) is a common but terrible thing: eof becomes true only after a reading operation returned nothing. That means that you will process the last line twice...
For your errors:
(4) _board[i] is an array, and an array cannot be on the left size of an assignment (idiomatically: it is not a lvalue)
(3): strcpy_s is not a drop-in replacement for strcpy and your compiler should have emit warnings (any correct compiler would have...). It should be:
strcpy_s(_board[i], COL, test);

#include <iostream>
#include <fstream>
#include <string>
#define ROW 25;
#define COL 80;
int i=0;
class Board
{
char _board[ROW][COL] = {0};
public:
Board(string name); // our new constructor - reads map from file.
};
Board::Board(string name)
{
fstream newfile;
newfile.open(name,ios::in);
if (newfile.is_open()){
string tp;
while(getline(newfile, tp)){
strcpy(_board[i], tp);
i++;
}
newfile.close();
}
}

Related

(C++) Creating two dimensional array from .dat file

I am trying to define a class CDTable, which has a variable double table[4][4000] (4 by 4000 array of doubles) and some functions that carry out calculations based on the table.
My CDTable.h looks something like:
#define CDTABLE_H
class CDTable {
public:
double table[4][4000];
CDTable(string fileName);
double dLookUp(double z);
};
and a part of my CDTable.cpp looks like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <ctime>
#include <stdlib.h>
#include "CDTable.h"
using namespace std;
CDTable::CDTable(string fileName) {
fstream file;
file.open(fileName.c_str(), ios::in);
string line;
int col = 0;
int row = 0;
getline(file, line); //skip the title line
while (getline(file, line, '\t')) { //for each line
istringstream ss(line);
double val;
while (ss >> val) { //read the value
table[row][col] = val; //assign the value
++col; //next column in the table
}
++row; //next line in the table
col = 0; //reset column
}
file.close();
}
int main() {
CDTable cd = CDTable("CDLookUp.dat");
return 0;
}
So, I mean to construct a CDTable object by giving it a string fileName which is a .dat file of two dimensional array (the first line of .dat file is not real data but a title line). I have other relevant methods implemented in CDTable.cpp as well, but I have not included them since they do not seem to be the problem.
CDTable.cpp compiles without any errors, but when I run it, I get Segmentation fault (core dumped).
Can somebody tell me what's wrong here? Is there a better way to convert a .dat or .txt two dimensional data to a two dimensional array of doubles in C++?

std::length_error when trying to output a string from class array

My program consists of three files. arithcard.hpp (header), assign2.cpp (the main program) and arithcard.cpp(method).
In the array, cards, is store strings read from a text file. For example, cards[0].fileLine has the string 2 + 2 = 4. (fileLine is a private member variable with all the strings), cards[1].fileLine has the string 2 + 4 = 3, etc...
I know cards[i].fileLine contains all these strings because I tested by printing them all out in the readCards method to see if they are actually in there.
Here is my problem, when I try to call cards[i].getQuestion (or .getAnswer()) in the main program. Sometimes, it shows me the question(or answer) or the error
"terminate called after throwing an instance of 'std::length_error'
what(): basic_string::_S_create"
arithcard.hpp
#include <iostream>
#include <string>
/*
Defines the class ArithCard, for handling arithmetic flash cards.
You may not modify the public method declarations provided below. The main
program used to test your solution will assume that these methods exist.
You can add private attributes and methods as you need them.
You may find it convenient to add additional public methods for testing.
Keep in mind that your code must work with the unmodified main program
or it will fail automated testing.
*/
class ArithCard {
public:
// Default constructor
ArithCard() ;
static bool readCards(const std::string &fileName,
int &cardCnt,ArithCard *&cards) ;
void displayQuestion(std::ostream &out) ;
bool checkAnswer(std::istream &in) ;
// Return the question as a string.
std::string getQuestion() ;
// Return the answer as a string.
std::string getAnswer() ;
// Return the answer as an integer.
int getAnswerValue() ;
private:
// Add your private methods and attributes here.
std::string fileLine;
std::string question;
std::string answer;
} ;
arithcard.cpp
#include <iostream>
#include <string>
#include <fstream>
#include "arithcard.hpp"
using namespace std;
ArithCard::ArithCard()
{
//body intentionally empty
}
bool ArithCard::readCards(const string &fileName, int &cardCnt, ArithCard *&cards)
{
//read the file line by line and store it in cards
return (true);
}
void displayQuestion(std::ostream &out)
{
//display output
}
bool checkAnswer(std::istream &in)
{
return (true);
}
// Return the question as a string.
string ArithCard::getQuestion()
{
size_t pos = 0;
pos = fileLine.find("=");
question = fileLine.substr(0, pos);
return question;
}
// Return the answer as a string.
string ArithCard::getAnswer()
{
size_t pos = 0;
pos = fileLine.find("=") + 1;
answer = fileLine.substr(pos);
return answer;
}
// Return the answer as an integer.
int getAnswerValue()
{
return answer;
}
assign2.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <limits>
#include <random>
#include "arithcard.hpp"
// File-local anonymous namespace
namespace {
int verbosity = 1 ;
}
/*
Read in the files of cards, then loop: query the user to specify a
question, print the question, check the answer. Terminate when the user
types an empty line instead of specifying a question.
*/
int main (int argc, const char *argv[])
{
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " <datafile>" << std::endl ;
return (1) ;
}
std::string dataFile(argv[1]) ;
bool result = false ;
int cardCnt = -1 ;
ArithCard *cards = nullptr ;
/*
Parse the file of questions & answers. A false return value indicates an
absent file or other i/o error. It's also possible the file is present but
contains no valid questions.
*/
result = ArithCard::readCards(dataFile,cardCnt,cards) ;
std::cout << cards[0].getQuestion() << std:: endl;
return (0) ;
}
From ยง21.4.2/1 [string.require],
If any operation would cause size() to exceed max_size(), that operation shall throw an exception object of type length_error.
So somewhere in your code you're attempting to create a string whose length exceeds string::max_size(), which is typically a huge number, so you should feel proud of yourself :-)
Jokes aside, it's difficult to tell where the error is because it looks like you've removed relevant sections of code, especially the implementation of ArithCard::readCards. I don't understand why you chose to make this function static and then pass it a pointer to an instance of ArithCard, instead of just making it a non-static member function.
Your code has the pointer you're passing to ArithCard::readCards initialized to nullptr, so I assume you're allocating memory for the object within the function. If you're not, then you most likely have undefined behavior going on within that function.
I'd change that function to
class ArithCard {
public:
...
bool readCards(const std::string &fileName, int &cardCnt) ;
};
And change the code within main() to
ArithCard cards;
result = cards.readCards(dataFile, cardCnt);
Also, in both getQuestion() and getAnswer() you're not checking the return value of string::find, so attempting to extract a substring using a invalid result may be the cause of this error. This is the most likely explanation because string::find will return string::npos, a huge number, if the search term is not found.

Can't read data from .dat file (VS2012 C++ project created from Simulink)

Edit:Thank you, The fixed code for those who are interested:
ert_main.cpp:
#include <stdio.h> /* This ert_main.c example uses printf/fflush */
#include "Rx.h" /* Model's header file */
#include "rtwtypes.h" /* MathWorks types */
#include <stdlib.h>
#include <iostream>
#include <istream>
#include <sstream>
#include <fstream>
#include <string>
//#include <ofstream>//for writing results to file
//#include <ifstream> //doesn't work
#include <vector>
#define lengthOFSignal 5000
at main func:
using namespace std;
std::vector<std::string> words;
std::string word;
ifstream iFile;
string path = __FILE__; //gets source code path, include file name
path = path.substr(0,1+path.find_last_of('\\')); //removes file name
string testFileName = "LEGACY_R12_800BITS_40MHz.dat";
path+= testFileName; //adds input file to path
int signal_length=0;
std::vector<real_T> real_part_VEC, imag_part_VEC;
std::istringstream ss;
real_T real_temp, imag_temp;
iFile.open(path,ios::binary );
//iFile.open(path.c_str(), ios::binary);
if (iFile.is_open()) {
while (std::getline(iFile, word)) {
words.push_back(word);
}
iFile.close();
}
signal_length=words.size();
for(int i=0; i< signal_length;i++)
{
ss.str(words[i]);
ss >> real_temp >> imag_temp;
real_part_VEC.push_back(real_temp);
imag_part_VEC.push_back(imag_temp);
}
real_T real_part[lengthOFSignal];
real_T imag_part[lengthOFSignal];
for (int i=0; i < signal_length; i++) {
real_part[i]=real_part_VEC[i];
imag_part[i]=imag_part_VEC[i];
}
/* Initialize model */
Rx_initialize(real_part,imag_part,signal_length);
The OLD code and problem :
The .dat file looks like two straight columnes with numbers (spaced)
I get an error regarding looping on the readed data (strtok -> atof (Null pointer) )
edited ert_main.cpp main function:
#include <stdio.h> /* This ert_main.c example uses printf/fflush */
#include "Rx.h" /* Model's header file */
#include "rtwtypes.h" /* MathWorks types */
#include <stdlib.h>
#include "mat.h"
#define lengthOFSignal 5000
#define SizeOfLine 35
int_T main(int_T argc, const char *argv[])
{
/* Unused arguments */
(void)(argc);
(void)(argv);
int i=0;
char bFileName[] = "QPSK_SISO_802_11_packet_awgn_fr_shft.dat";
char chr[SizeOfLine*lengthOFSignal];
char *token;
real_T real_part[lengthOFSignal];
real_T image_part[lengthOFSignal];
int signal_length=0;
std::ifstream iFile(bFileName, std::ios::binary);
iFile.getline(chr,100);
for(int i=0; i<lengthOFSignal; i++) {
if (chr== NULL) break;
token= strtok(chr," ");
real_part[i]=atof(token); // real part.---problem occurs here!!!!
token= strtok(NULL," ");
image_part[i]=atof(token);// imaginary part.
iFile.getline(chr,100);
signal_length++;
}
iFile.close();
/* Initialize model */
Rx_initialize(real_part,image_part,signal_length);
/* Attach rt_OneStep to a timer or interrupt service routine with
* period 40.0 seconds (the model's base sample time) here. The
* call syntax for rt_OneStep is
*
* rt_OneStep();
*/
printf("Warning: The simulation will run forever. "
"Generated ERT main won't simulate model step behavior. "
"To change this behavior select the 'MAT-file logging' option.\n");
fflush((NULL));
while (rtmGetErrorStatus(Rx_M) == (NULL)) {
/* Perform other application tasks here */
rt_OneStep();
if(Rx_Y.EVM!=0) break;
}
/* Disable rt_OneStep() here */
/* Terminate model */
Rx_terminate();
return 0;
}
link to the solution (VS 2012)
link to the project/solution
You are trying to convert more than the input length. That is creating the debug assertion error. As a suggestion, try to read the data in as numbers. Makes life a lot easier.
Edit: I am adding onto the previous statement. I have used istringstream to parse the string into a number. I just checked this for a number but you can easily expand this.
std::string str("2.1506668e-03");
std::istringstream ss;
ss.str(str);
double x;
ss >> x;
std::cout << x << std::endl;
Ans: 0.0021567
New edit: Ah! This code is much better. But you still need to iron out some very basic errors.
1> The file.is_open failing can only be due to the file not being found. Try to find out if the file is in the search path. The easiest way to do it is copying the file onto the project file folder.
2> Using vectors always make sense when the size is undetermined. Btw, you can determine the size of a file and thus the size of the arrays using fseek and ftell.
3> Just a cursory glance reveals that this statement std::string real_str("words[i]");should be changed to std::string real_str(words[i]); The previous one takes the string words[i] as input.
4> In the for loop, you are looping for the signal_length but you are using words[i] and words[i+1]. So only half the vector would be read in such a case.
I would just read the line as a whole into the word vector and then parse it into real and imaginary parts
std::vector<std::string> words;
std::string word;
if (fin.is_open()) {
while (std::getline(fin, word)) {
words.push_back(word);
}
fin.close();
}
// I would declare two vectors
std::vector<real_T> real_part, imag_part;
std::istringstream ss;
real_T real_temp, imag_temp;
// for loop
for(int i=0;i<words.size();i++)
{
ss.str(words[i]);
ss >> real_temp >> imag_temp;
real_part.push_back(real_temp);
imag_part.push_back(imag_temp);
}

Inputting a file into a structure

I am trying to read the lines from a file called 'weapon.txt' and input them into a structure something a long the lines of this
struct weapon
{
char name[20]; //Edited
int strength;
}
The file to be read looks like this:
Excalibur
150
Throwing Stars
15
Rapier
200
Bow and Arrow
100
Axe
200
Crossbow
100
Scimitar
250
Rusted Sword
10
Soul Slayer
500
The code I have right now is
#include<fstream>
#include<iostream>
#include<cstring>
using namespace std;
struct WeaponInfo
{
char name[16];
int strength;
};
const int MaxWeap = 10;
void openfile(ifstream&); //Opening the file
void displayfile(ifstream&, WeaponInfo&);//Display file
int main ()
{
WeaponInfo weapon[MaxWeap];
ifstream fin;
openfile(fin);
displayfile(fin, weapon[MaxWeap]);
}
void openfile(ifstream& fin)
{
fin.open("weapon.txt");
}
void displayfile(ifstream& fin, WeaponInfo& weapon[MaxWeap])
{
char nm;
int str;
while (fin.eof() == 0)
{
for(int i = 0; i <= MaxWeap; i++);
{
fin.getline(nm);
fin.getline(str);
strcpy(weapon[i].name, nm);
strcpy(weapon[i].strength, str);
i++;
cout << weapon[i].name << "\n" << weapon[i].strength << endl;
}
}
fin.close();
}
EDIT: This is what I have right now after re-doing it, I am getting compile errors of : declaration of 'weapon' as array of references; In function 'void displayfile(...) 'fin' was not declared in this scope; 'weapon' is not declared in this scope; ma,e lookup of 'i' changed for ISO 'for' scoping [-fpermissive].
I'd firstly tend to use std::string rather than char arrays - they're just easier to work with. So the structure noww looks like this:
struct weapon
{
string name;
int strength;
};
Next you need something that will read the structure from an input stream:
bool getWeapon( ifstream& is, weapon& w )
{
getline(is, w.name) ;
string strengthStr;
getline(is, strengthStr) ;
w.strength = strtol( strengthStr.c_str(), NULL, 0 );
return !is.eof();
}
Two things here, I've used strtol as a conversion function from string to int. atoi is used but strtol gives you slightly more flexibility and crucially, better error cchecking, alkthough I've not bothered to implement it here. A stringstream might have been another alternative here.
Secondly, I return a boolean indicating whether the name was empty. The reason for this is that when, later in the code, I check for eof() on the ifstream, it isn't actually set until you read past the end of the file. So the last good read will not set it but the first attempt to reead past it will. Returning false here then will indicate to the caller that the 'get' failed due to the ifstream being at end of file.
Lastly, we need something to read all of the weappons in:
ifstream input;
input.open("weapons.txt");
vector<weapon> ws;
if ( input )
{
while (! (input.eof()))
{
weapon w;
if ( ! getWeapon( input, w ) )
break;
ws.push_back( w );
}
}
input.close();
This wwill place all the weapons into a vector. Note the call to getWeapon breaks if it failed to prrevent adding on an 'empty' weapon. Not the most glamorous solution but it should work.
Pseudo-code goes something like this, (and like Martol1ni has coded for you):
open the file
while (!end-of file)
{
create instance of struct weapon
read a line and strcpy into weapon.name
read a line and set weapon.strength = atoi(line)
do something with the instance, eg. add to list, call a member function, etc.
}
loop
close file.
Assuming you control the weapons.txt, don't bother checking for errors in the file, you can do this. Next time, do a little research... :)
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
#include <cstdlib>
using namespace std;
struct weapon
{
string name;
int strength;
weapon(string n, int s) : name(n), strength(s) {}
};
void readFileToVec(vector<weapon> &myVec) {
ifstream in("weapon.txt");
while (!in.eof()) {
string name;
getline(in,name);
string strength;
getline(in,strength);
weapon myWep(name,atoi(strength.c_str()));
myVec.push_back(myWep);
}
in.close();
}

Using the fstream getline() function inside a class

I'm trying to load lines of a text file containing dictionary words into an array object. I want an array to hold all the words that start with "a", another one for "b" ... for all the letters in the alphabet.
Here's the class I wrote for the array object.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class ArrayObj
{
private:
string *list;
int size;
public:
~ArrayObj(){ delete list;}
void loadArray(string fileName, string letter)
{
ifstream myFile;
string str = "";
myFile.open(fileName);
size = 0;
while(!myFile.eof())
{
myFile.getline(str, 100);
if (str.at(0) == letter.at(0))
size++;
}
size -= 1;
list = new string[size];
int i = 0;
while(!myFile.eof())
{
myFile.getline(str, 100);
if(str.at(0) == letter.at(0))
{
list[i] = str;
i++;
}
}
myFile.close();
}
};
I'm getting an error saying:
2 IntelliSense: no instance of overloaded function "std::basic_ifstream<_Elem, _Traits>::getline [with _Elem=char, _Traits=std::char_traits<char>]" matches the argument list d:\champlain\spring 2012\algorithms and data structures\weeks 8-10\map2\arrayobj.h 39
I guess it's requiring me to overload the getline function, but I'm not quite certain how to go about or why it's necessary.
Any advice?
the function for streams that deals with std::string is not a member function of istream but rather a free function it is used like so. (the member function version deals with char*).
std::string str;
std::ifstream file("file.dat");
std::getline(file, str);
It is worth noting there are better safer ways to do what you are trying to do like so:
#include <fstream>
#include <string>
#include <vector>
//typedeffing is optional, I would give it a better name
//like vector_str or something more descriptive than ArrayObj
typedef std::vector<std::string> > ArrayObj
ArrayObj load_array(const std::string file_name, char letter)
{
std::ifstream file(file_name);
ArrayObj lines;
std::string str;
while(std::getline(file, str)){
if(str.at(0)==letter){
lines.push_back(str);
}
}
return lines;
}
int main(){
//loads lines from a file
ArrayObj awords=load_array("file.dat", 'a');
ArrayObj bwords=load_array("file.dat", 'b');
//ao.at(0); //access elements
}
don't reinvent the wheel; checkout vectors they are standard and will save you a lot of time and pain.
Final try not to put in using namespace std that is bad for a whole host of reasons I wont go into; instead prefix std objects with std:: so like std::cout or std::string.
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/string