I'm trying to read a CSV file using 2d array but there's a problem with the reading. The first cell of the file is skipped and then continues read all. I don't understand why it doesn't read the first cell.
#include<iostream>
#include<fstream>
#include<cstring>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string arrival,job[3][4];
ifstream jobfile("myfile.csv");
std::string fileCommand;
if(jobfile.is_open())
{
cout << "Successfully open file"<<endl;
while(getline(jobfile,arrival,','))
{
for(int i=1;i < 4;i++) //i = no. of job
{
for(int j=0; j<4; j++) // j = no. of processes
{
getline(jobfile,job[i][j],',');
cout << "Job[" << i << "]P[" << j << "]: "<< job[i][j]<< endl;
}
}//end for
}//end while
}//end if for jobfile open
jobfile.close();
}
Change this:
for(int i=1;i < 3;i++)
to this:
for(int i=0;i < 3;i++)
Also, remove this getline(jobfile,job[i][j],',');, since you skip a line that way. When you called getline in the condition of the while loop, it already read a line (as a result, now, you have to store that line. Then, when the condition of the while loop is evaluated again, the next line will be read).
However, it gets much more complicated than this, since you arrival will hold one token at a time, until it meets the last token of the current line. In that case, arrival will be this: "currentLineLastToken\nnextLineFirstToken".
For that reason, you need to specially handle the case that arrival contains a newline, use string::find for this.
When a newline is found, you should split that string to that newline, in order to extract the two tokens involved. Use string::substr for this.
Moreover, you shouldn't loop inside the while loop with a double for to store the token, you just read. Use a double for loop, when it is time to print job, only after exiting the while loop that read the file.
Putting everything together, we get this:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string arrival,job[3][4];
ifstream jobfile("myfile.csv");
std::string fileCommand;
if(jobfile.is_open())
{
cout << "Successfully open file"<<endl;
int i = 0, j = 0;
while(getline(jobfile,arrival,','))
{
//cout << "|" << arrival << "|" << endl;
size_t found = arrival.find("\n");
if (found != std::string::npos) // if newline was found
{
string lastToken = arrival.substr(0, found);
string nextLineFirstTOken = arrival.substr(found + 1);
job[i++][j] = lastToken;
j = 0;
if(nextLineFirstTOken != "\n") // when you read the last token of the last line
job[i][j++] = nextLineFirstTOken;
}
else
{
job[i][j++] = arrival;
}
}//end while
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 4; ++j)
{
cout << job[i][j] << " ";
}
cout << endl;
}
}//end if for jobfile open
jobfile.close();
}
Output (for my custom input):
Successfully open file
aa bb cc dd
bla blu blo ble
qq ww ee rr
Related
So I am reading in a file of zeros and ones.
1,1,1,0,0,0,0,0
1,1,1,0,1,1,0,0
1,1,1,0,1,1,0,0
1,1,1,0,0,0,1,0
1,1,1,0,0,0,1,0
1,1,1,0,0,0,1,0
1,1,1,0,0,1,1,0
1,1,1,0,0,0,0,0
I read in this file and store it into a 2d vector. I then print this 2D vector and get these results as output.
\311[\240\3778\311[\240\377P\311[\240\377h\311[\240\377\200\311[\240\377\230\311[\240\377\260\311[\240\377\310\311[\240\377\340\311[\240\377\370\311[\240\377\312[\240\377(\312[\240\377#\312[\240\377X\312[\240\377p\312[\240\377\210\312[\240\377\240\312[\240\377\270\312[\240\377\320\312[\240\377\350\312[\240\377\313[\240\377\313[\240\3770\313[\240\377H\313[\240\377`\313[\240\377x\313[\240\377\220\313[\240\377\250\313[\240\377\300\313[\240\377\330\313[\240\377\360\313[\240\377\314[\240\377 \314[\240\3778\314[\240\377P\314[\240\377h\314[\240\3771110+2+,0,+a_0co0%We0Enab1AK1ages1eKey0r_1ons_1rvic0_000069631Ap1SUse1co0PKSe1NSLi1e_0"NSA0led_1tion1NSPr1DMSE0ging0mptD0ionE1sDat0appl1A_001D6961y_0mati0$NSA0able1nEna0sRequested_Microsoft Controller_#NSAutomaticQuoteSubstitutionEnabled\Dell S2830dn_AppleMiniaturizeOnDoubleClickQ1 \2410Uen-US3A\300\274\265\302\317+w\32134VdirMap\320 U10.14\241:\323;<=>?#WreplaceTwithRonSomwZOn my way!"?\2003A\300\321i\245z% XMaximizeUen_US\321GH_NSWebServicesProviderW,\200\306IJKL_qDisplayName_NSProviderIdentifierVGoogle^com.google.www 3A\300\321j
\273\375 3A\300\320Sa.$p\245RSTUV_0~/Desktop/CompSci 2100/2100Project3/2100Project3_ ~/Desktop/CompSci 2100/Project_2_~/Desktop/CompSci 2100_#~/Desktop/CompSci 2110/2210project2_0~/Desktop/CompSci 2110/2210Project3/2210Project3#?\340TDark \244]E^_RenRtrRfr _{\233\303\333\361 =_s\221\300\333\3709Y}\232\277\322\355\371*Hc\206\241\265\3223Z\201\244\306\335023457=FIPQRTZ\^emruy\204\206\213\224\225\236\244\247\310\315\344\373%+^\201\232\300\363\374 binput1.txt
\377\377\377\377\377q\205<оa\310\214 CPX#\360dCFPreferencesMessages\340#
\360\200CFPreferencesShmemName\220apple.cfprefs.501v1CFPreferencesShmemIndex0\364CFPreferencesShmemState#\360\200CFPreferencesShmemName\220apple.cfprefs.501v1CFPreferencesShmemIndex0\245CFPreferencesShmemState#\360\200CFPreferencesShmemName\220apple.cfprefs.501v1CFPreferencesShmemIndex0\343CFPreferencesShmemState#\360\200CFPreferencesShmemName\220apple.cfprefs.501v1CFPreferencesShmemIndex0YCFPreferencesShmemState#\360TCFPreferencesShmemName\220apple.cfprefs.501v1CFPreferencesPropertyList\200\255bplist00\337
234_com.apple.trackpad.version_.com.apple.trackpad.fourFingerHorizSwipeGesture_.com.apple.trackpad.fourFingerPinchSwipeGesture_.com.apple.trackpad.fiveFingerPinchSwipeGesture_com.apple.mouse.tapBehavior_ com.apple.trackpad.rotateGesture_com.apple.ColorSync.Devices_'com.apple.trackpad.enableSecondaryClick_com.apple.trackpad.pinchGesture_!com.apple.trackpad.scrollBehavior_5com.apple.trackpad.twoFingerFromRightEdgeSwipeGesture_)com.apple.trackpad.threeFingerDragGesture_(com.apple.trackpad.threeFingerTapGesture_/com.apple.trackpad.threeFingerHorizSwipeGesture_-com.apple.trackpad.fourFingerVertSwipeGesture_.com.apple.trackpad.threeFingerVertSwipeGesture_#PKSecureElementAvailableFlagsByHost_!com.apple.trackpad.momentumScroll_,com.apple.trackpad.twoFingerDoubleTapGesture \322+_0Device.cmra.63306330-3362-6536-3839-633063343435_0Device.mntr.C07EE717-D5E0-4933-131D-70E3DC02779B\322!_DeviceDescriptions_FactoryProfiles\321 Uen_USViPhone\322"#$*Y555810816_DeviceDefaultProfileID\322%&')_DeviceModeDescriptions_DeviceProfileURL\321(WDefault_[/System/Library/Frameworks/ICADevices.framework/Versions/A/Resources/Camera RGB Profile.iccY555810816\321,-^CustomProfiles\321./Q1_:/System/Library/ColorSync/Profiles/Generic RGB
it is actually a lot more than this but I think that would be too much for a question. It prints stuff like this sometimes only one sentence long sometimes forever. I have never experienced something like this I am just trying to print a 2D vector I have done this 1,000's of times with no problems. I am using xCode and here is my code for the whole project.
//read in the file into a double vector
#include <iostream>
#include <vector>
#include <string>
#include <stdlib.h>
#include <fstream>
#include <sstream>
using namespace std;
class OBJs{
public:
string Obj;
int numItemsInObj;
};
//vector to store all of the data for the grid and the row of the big vector
vector<OBJs> row;
vector<vector<OBJs>> grid;
//maybe create an object for the found parameters
OBJs tempObj;
//functions
void load(string fileName);
void printObjs();
int main(int argc, const char * argv[]) {
string file;
cout << "Please enter your filename here: ";
cin >> file;
load(file);
printObjs();
return 0;
}
void load(string fileName){
//read in a line and insert the line(string) into the second index of the vector
string line;
string zeroOrOne;
ifstream file;
file.open(fileName);
//basically a guard let function in swift
if(!file){
cout << "Could not open the file " << fileName << endl;
//exit(0);
}
// you have successfully entered the file specified
while(getline(file, line)){
//grabbing each line of the file into the var line
//delimit this line by , in getline
istringstream ss(line);
while(getline(ss, zeroOrOne, ',')){
//put it into the row vector.
tempObj.Obj = zeroOrOne;
tempObj.numItemsInObj = 0;
row.push_back(tempObj);
}
//put the row in the grid.
grid.push_back(row);
}
file.close();
}
void printObjs(){
for(int i =0; i < grid.size(); i++){
for(int j =0; j< row.size(); j++){
if(grid[i][j].Obj == ""){
//cout << "nothing in this element" << endl;
} else {
cout << grid[i][j].Obj;
}
}
cout << endl;
}
}
In printObjs() you are limiting the loop index j with row.rize():
for(int j =0; j< row.size(); j++)
but use it to index into grid with grid[i][j].Obj. There is no reason that the size of row should be equal to that of grid[i]. Therefore you probably are accessing out-of-bounds causing undefined behavior.
It should probably be for(int j =0; j< grid[i].size(); j++) instead.
You also shouldn't be using global variables if it is not necessary. Both tmpObj and row are only used in load. Therefore declare them there.
Similarly grid can be a local variable, passed around between the functions.
There are couple of problems in your code. Firstly:
while (getline(file, line)) {
istringstream ss(line);
while (getline(ss, zeroOrOne, ',')) {
tempObj.Obj = zeroOrOne;
tempObj.numItemsInObj = 0;
row.push_back(tempObj);
}
grid.push_back(row);
}
Notice what's happening. You read every number per single line, add it to row and then add row to grid. What happens when you read the second line? You read more numbers and add more numbers to row. Now your row contains numbers from both first and second lines. You want to clear the row after copying it to the next element in the grid, like so:
while (getline(file, line)) {
istringstream ss(line);
while (getline(ss, zeroOrOne, ',')) {
tempObj.Obj = zeroOrOne;
tempObj.numItemsInObj = 0;
row.push_back(tempObj);
}
grid.push_back(row);
row.clear();
// ^ notice the clear() call here
}
There is also another issue. Here:
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < row.size(); j++) {
if (grid[i][j].Obj == "") {
//cout << "nothing in this vector" << endl;
} else {
cout << grid[i][j].Obj;
}
}
cout << endl;
}
you don't want to check for row.size(). You want to operate on the grid and you want the length of the ith row of the grid. Simply change it to:
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[i].size(); j++) {
// notice the change here ^^^
if (grid[i][j].Obj == "") {
//cout << "nothing in this vector" << endl;
} else {
cout << grid[i][j].Obj;
}
}
cout << endl;
}
I'm in the process of writing the program and stumbled upon a few issues.
The code reads a text file, which contains a list of 20 string words. The function playHangman() is supposed to read the file and randomly picks one word, which is displayed as asterisks in the console. The code works fine with local words when the function is called. For example Playhangman("stackOverflow"), will show the exact number of characters and will loop through them until the word is guessed right. If you take a look at the code, I'm calling the random word into the function. That word is stored as array. I know that that's not the proper way to do randomize, but for now, even if it picks the same word over and over, that's Ok, I just need to make sure it actually reads the array. The other thing is, when all characters are revealed, all the words on that text file are displayed, looks like I'm calling the entire content of the array instead of just that random word that's supposed to be generated.
Any help would be appreciated, thank you!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string word[20];
string randomWord = word[rand() % 20];
int playHangman(string randomWord) {
int misses = 0;
int revealedletters = 0;
string display = randomWord;
ifstream textFile;
// Open file
textFile.open("hangman.txt");
// Check if file exists
if (!textFile) {
cerr << "Unable to open text file\n";
exit(1); // Call system to stop
}
else {
cout << "File opened successfully. Program will continue...\n\n";
// Loop through the content of the file
while (textFile >> randomWord) {
for (int i = 0; i < display.length(); i++)
display[i] = '*';
while(revealedletters < randomWord.length()) {
cout << "Misses: " << misses << endl;
cout << "Enter a letter in word ";
cout << display << " : ";
char response;
cin >> response;
bool goodGuess = false;
bool duplicate = false;
for (int i = 0; i < randomWord.length(); i++)
if (response == randomWord[i]) {
if (display[i] == randomWord[i]) {
cout << response << " is already in the word." << endl;
duplicate = true;
break;
}
else {
display[i] = randomWord[i];
revealedletters++;
goodGuess = true;
}
}
if (duplicate)
continue;
if (!goodGuess) {
misses++;
cout << response << " is not in word\n";
}
}
cout << "You guessed right! The word is " << randomWord << ".\n";
}
return misses;
}
}
// TODO: Do you want to guess another word, Y/N?
int main () {
playHangman(randomWord);
// TODO: number of misses to guess the word.\n";
}
In your declaration and initialisation of your global variables:
string word[20];
string randomWord = word[rand() % 20];
word is an array of 20 empty strings and therefore randomWord will also always be empty.
In your playHangman function you have:
while (textFile >> randomWord) {
for (int i = 0; i < display.length(); i++)
display[i] = '*';
while(revealedletters < randomWord.length()) {
......
This reads a single word from the file into randomWord, plays the game with that word then loops round to read the next word and plays again with that word. As revealedletters doesn't get reset the game will finish immediately if the first word is longer than the next one.
I think the code you actually want looks something like this (remove your global variables too):
std::string word;
std::vector<std::string> words;
while (textFile >> word) {
words.push_back(word);
}
randomWord = words[rand() % words.size()];
std::string display = std::string(randomWord.size(), '*');
while(revealedletters < randomWord.length()) {
......
If you really must use arrays:
const size_t maxWords = 20;
std::string words[maxWords];
size_t wordCount = 0;
while (textFile >> word && wordCount < maxWords) {
words[wordCount++] = word;
}
randomWord = words[rand() % wordCount];
std::string display = std::string(randomWord.size(), '*');
while(revealedletters < randomWord.length()) {
......
I am trying to read a single character multiple times. The catch is that I need to prevent user errors. So for example:
char arr[10];
for(int i = 0; i < 10; i++)
{
cin.get(arr[i]);
}
Where the inputs should be something like a, b, c, d, .... But if someone were to enter ab for the first entry I want to capture the a and then ignore the b. I know about cin.ignore however I don't know how I would go about ignoring an arbitrary number of alphanumeric characters or symbols considering that I want to ignore a potentially unlimited number of characters and then stop ignoring and read again.
How can I either ignore an arbitrary number of characters and then stop ignoring or how can I actually flush the buffer for cin.
Most input is line feed so if you want to ignore all characters in the input stream until you hit a newline then you could use:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
Since we ignore up to the streamsize there should not be an extra content in the input buffer.
If you want user to hit enter after each symbol, then code could be as simple as this:
char arr[10];
for(int i = 0; i < 10; )
{
std::string line;
std::getline( std::cin, line );
// check that line is not empty
if( line.empty() ) {
std::cout << "missing input" << std::endl;
continue;
}
arr[i++] = line[0]; // get only first symbol and ignore the rest
}
if you have something else in mind, I am afraid that will not work with std::cin - you do not see any input until user presses enter. In that case you would have to use OS specific functions to get unbuffered input.
The following is the code that you want, if your inputing like this a 'enter' b 'enter' c 'enter' etc...
#include <iostream>
#include <string>
using namespace std;
int main() {
char arr[10];
string line;
for (int i = 0; i < 10; i++)
{
getline(cin, line);
arr[i] = line[0];
cout << endl << "Here is the Char: " << arr[i] << endl;
}
return 0;
}
BUT if you enter input like this in one line: a,b,c,d,e,f,g,h,i,j 'enter' then you want the following code:
#include <iostream>
#include <string>
using namespace std;
int main() {
char arr[10];
string line;
int i = 0;
size_t end;
getline(cin, line);
end = 0;
int counter = 0;
if (line != "") {
while (end != string::npos && counter < 10) {
if (counter == 0) {
arr[counter] = line[0];
}
else {
end = line.find(",", end + 1);
arr[counter] = line[end + 1];
}
counter++;
}
}
for (int i = 0; i < 10; i++) {
cout << endl << "Here is the Char: " << arr[i] << endl;
}
return 0;
}
Would like to fill an array one line at a time from the file "Hello.cpp". However if I do it the way below I fill the entire file [w] times instead of just grabbing one line from the file for each iteration of i.
If I remove the { } from getline then the array is filled with the last line of "Hello.cpp" [w] times.
I am not sure how to get a new [i] each time from the Hello.cpp file.
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main() {
int w=0;
ifstream in("Hello.cpp");
string s;
while(getline(in, s))
w=w+1; //first count the number of lines in the file for the array
string a[w];//make an array big enough for the file
for(int i = 0; i < w ; i++) {
ifstream in("Hello.cpp");
string s;
while(getline(in, s)){
a[i] = s;
cout << i + 1 << " " << s << endl;
}
}
I would close your file before reopening it (best practice).
Looks to me like you need to move your file open (ifstream constructor) outside of your for (do you really want to open the file w times)? Since you bother to count the lines first don't you really want something like this:
ifstream in1("Hello.cpp");
for(int i = 0; i < w ; i++) {
getline(in1, a[i]);
cout << i + 1 << " " << a[i] << endl;
}
I created a text file love.txt:
i love you
you love me
How do I store them into separate array, namely line1 and line2 and then display them out in console?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line1[30];
string line2[30];
ifstream myfile("love.txt");
int a = 0;
int b = 0;
if(!myfile)
{
cout<<"Error opening output file"<<endl;
system("pause");
return -1;
}
while(!myfile.eof())
{
getline(myfile,line1[a],' ');
cout<<"1."<<line1[a]<<"\n";
getline(myfile,line2[b],' ');
cout<<"2."<<line2[b]<<"\n";
}
}
Try specifying the last argument as '\n' in both getline() functions:
getline(myfile, line1[a], '\n');
instead of
getline(myfile, line1[a], ' ');
How about this.. .
vector <string> v;
string line;
ifstream fin("love.txt");
while(getline(fin,line)){
v.push_back(line);
}
You can think of a string as an array of characters, so you will only need one array of strings:
const size_t SIZE = 30;
string line[SIZE]; // creates SIZE empty strings
size_t i=0;
while(!myfile.eof() && i < SIZE) {
getline(myfile,line[i]); // read the next line into the next string
++i;
}
for (i=0; i < SIZE; ++i) {
if (!line[i].empty()) { // print only if there is something in the current line
cout << i << ". " << line[i];
}
}
You could maintain a counter to see how many lines you have stored into (instead of checking for empty lines) as well -- this way you will properly print empty lines as well:
const size_t SIZE = 30;
string line[SIZE]; // creates SIZE empty strings
size_t i=0;
while(!myfile.eof() && i < SIZE) {
getline(myfile,line[i]); // read the next line into the next string
++i;
}
size_t numLines = i;
for (i=0; i < numLines; ++i) {
cout << i << ". " << line[i]; // no need to test for empty lines any more
}
Note: you will be able to store only up to SIZE lines. If you need more, you will have to increase SIZE in the code. Later on you will learn about std::vector<> that allows you to dynamically grow the size as needed (so you won't need to keep track of how many you stored).
Note: the use of constants like SIZE allows you to change the size in one place only
Note: you should add a check for errors in the input stream on top of eof(): in case there was a read failure other than reaching the end of the file:
while (myfile && ...) {
// ...
}
here myfile is converted to a boolean value indicating if it is OK to use it (true) or not (false)
Update:
I just realized what you are after: you want to read the input as series of words (separated by space), but display them as lines. In this case, you will need arrays-of-arrays to store each line
string line[SIZE1][SIZE2];
where SIZE1 is the maximum amount of lines you can store and SIZE2 is the maximum amount of words you can store per line
Filling this matrix will be more complex: you will need to read the input line-by-line then separate the words within the line:
string tmp; // temporary string to store the line-as-string
getline(myfile, tmp);
stringstream ss(tmp); // convert the line to an input stream to be able to extract
// the words
size_t j=0; // the current word index
while (ss) {
ss >> line[i][j]; // here i is as above: the current line index
++j;
}
Output:
for (i=0; i < numLines; ++i) {
cout << i << ". ";
for (size_t j=0; j < SIZE2; ++j) {
if (!line[i][j].empty()) {
cout << line[i][j] << " ";
}
}
}
My complete solution.
the config.txt file contains:
#URL WEB POP3 IMAP SMTP FTP DNS PING ORDER
st-xxxx.com 1 1 0 1 1 0 1 1
24.xxx.195.11 1 1 0 1 1 0 1 2
24.xxx.195.12 1 1 0 1 1 0 1 3
192.168.0.100 1 1 0 1 1 0 1 4
and my code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
ifstream myfile("config.txt");
if(!myfile)
{
cout<<"Error opening output file"<<endl;
system("pause");
return -1;
}
const size_t SIZE1 = 30;
const size_t SIZE2 = 10;
string line[SIZE1][SIZE2];
string tmp; // temporary string to store the line-as-string
size_t i=0; // the current line index
size_t j=0; // the current word index
while(!myfile.eof() && i < SIZE1) {
getline(myfile, tmp);
stringstream ss(tmp); // convert the line to an input stream to be able
//to extract the words
size_t j=0;
while (ss) {
ss >> line[i][j]; // here i is as above: the current line index
++j;
}
i++;
}
size_t numLines = i;
cout << numLines << "\n";
for (i=1; i <= numLines; ++i) {
for (size_t j=0; j < SIZE2; ++j) {
if (!line[i][j].empty()) {
cout << line[i][j] << " ";
}
}
cout << "\n";
}
cout << line[3][0] << "\n"; // print the third line first word
}
Hope tht helps anybody who is searching for this type of solution, even if the post is quite old.