Atoi function while reading a .csv file C++ - c++

The execution of my code crashes when it gets to the "atoi" function, but I cannot understand why.
The code is supposed to read a matrix from a .csv file, considering:
- the first row (so till the first '\n') and saving each element (separated by a ',') in a vector of ints; - the rest of the matrix, by looking at each element and creating a specific object if the number read is 1 or 2.
I don't get any exception while debugging the program, it just crashes during the execution (and using the system ("PAUSE") I could figure out it was the atoi function which didn't work properly).
Can you help me understand what is going wrong?
Thank you very much.
Ps: I also attached all the libraries I'm loading... maybe it can help :)
#include <fstream>
#include <stdio.h>
#include <sstream>
#define nullptr 0
#include <string>
#include "classi.h"
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
ifstream file("problem.csv");
unsigned int N = 0;
unsigned int M = 0;
char c; //modificato char * c;
unsigned int i=0,j=0, k=0, n_iter, j_temp =0;
std::vector<car> v_row;
std::vector<car> v_col_temp;
std::vector<int> iter; // location where I want to save the ints corresponding to the elements of the first row of the .csv file //
std::string iterazioni; //location where I want to save the first row as a string and then cut it into pieces (iteraz) and then convert (atoi --> iter)
std::string iteraz;
while(!file.eof()){
std::getline(file,iterazioni,'\n');
stringstream it(iterazioni);
while (it.good()) {
std::getline(it,iteraz, ',');
iter[k] = atoi(iteraz.c_str());
if(iter[k]<0){
cout<<"Errore: negative #of iterations"<<endl;
break;
}
iter.push_back(0);
k++;
}
iter.pop_back();
file.get(c);
if (c=='1'){
blue_car b(i,j);
if (v_col_temp[i].get_next() != nullptr)
v_col_temp[i].insert_tail(&b);
else
v_col_temp[i].insert_head(&b);
}
if (c=='2'){
red_car r(i,j);
if (v_row[i].get_next() != nullptr)
v_row[i].insert_tail(&r);
else
v_row[i].insert_head(&r);
}
if (c==',') {
j++;
if (i == 0)
j_temp++;
}
if (c=='\n'){
car p;
v_row.push_back(p);
v_col_temp.push_back(p);
i++;
if (j != j_temp) {
std ::cout<<"errore input non valido: numero righe/colonne non coerente"<<endl;
}
j=0;
}
else if ((c!='\n') && (c!=',') && (c!='0') && (c!='1') && (c!='2'))
std ::cout<<"errore input non valido"<<endl;
};
n_iter = k-1;
M=i;
N=j+1;
...

Your program crashes because you failed to initialize the contents of the iter vector.
std::vector<int> iter; // location where I want to save the ints corresponding to the elements of the first row of the .csv file //
You declare and construct this vector. The vector is empty at this point, and it has no elements.
At some point later:
iter[k] = atoi(iteraz.c_str());
The initial value of k is 0, so this attempts to assign the return value from atoi() to iter[0].
The problem is, of course, there is no iter[0]. The iter vector is still empty, at this point.
Additional comments, which is sadly true for at least 50% of these kinds of questions on stackoverflow.com:
1) "using namespace std"; is a bad practice, that should be avoided
2) Do not use system("pause") as well, as you referenced in your question.

Related

How to check if a string ends with 'ed' in C++;

How to write a program that reads 5 strings from user input and prints only those strings that end with the letter ‘ed’ in C++. Need help!
The solution is rather straightforward.
First we define a container that can contain 5 std::string. For that we use a std::vector together with a constructor to reserve space for the 5 elements.
Then we copy 5 strings from the console (from user input) into the vector.
And, last, we copy elements out of the std::vector to std::cout, if the strings end with "ed".
Because of the simplicity of the program, I cannot explain much more . . .
Please see.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <iterator>
constexpr size_t NumberOfTexts = 5U;
int main()
{
// Define a container that can hold 5 strings
std::vector<std::string> text(NumberOfTexts);
// Read 5 strings from user
std::copy_n(std::istream_iterator<std::string>(std::cin), NumberOfTexts, text.begin());
// Print the strings with ending "ed" to display
std::copy_if(text.begin(), text.end(), std::ostream_iterator<std::string>(std::cout,"\n"), [](const std::string& s){
return s.size()>=2 && s.substr(s.size()-2) == "ed";
});
return 0;
}
Simple solution,
#include<iostream>
using namespace std;
bool endsWith(const std::string &mainStr, const std::string &toMatch)
{
if(mainStr.size() >= toMatch.size() &&
mainStr.compare(mainStr.size() - toMatch.size(), toMatch.size(), toMatch) == 0)
return true;
else
return false;
}
int main()
{
string s[5];
for(int i=0;i<5;i++)
{
cin>>s[i];
}
for(int i=0;i<5;i++)
{
if(endsWith(s[i],"ed"))
cout<<s[i]<<endl;
}
}
Hope This might Helps:)

Scanning User Input for Strings Declared in an Array

I am creating a program that scans user input for words that are listed in an array. The find() function seems like it'll work, but I can't find anything showing how to implement it for what I want to do. I'm pretty new to programming (obviously).
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string subj [5]={"I","He","She","We","They"};
string verb [5]={" like"," hate"," sacrifice"," smell"," eat"};
string obj [5]={" bacon","s cats","s bagels","s children","s cops"};
string greeting [5]={"How are you","How's it going","Sup dude","Hey","Hello"};
string negvibe [4]={"bad","terrible","lousy","meh"};
string userfeeling;
int main()
{
srand(time(0));
int rando = rand() %5;//generates a random number between 0 and 4
int rando1 = rand() %5;
int rando2 = rand() %5;
cout << greeting [rando1] << "." << endl;
getline(std::cin,userfeeling);
if .... // What has to be done here?
find(negvibe, negvibe + 4, userfeeling) != negvibe + 4);
// Something like that?
// then ...
{
cout << subj[rando] << verb[rando1] << obj[rando2] <<"." <<endl;
}
return 0;
}
To make find work properly you should user iterators like so
if(find(std::begin(negvibe), std::end(negvibe), userfeeling) != std::end(negvibe)){
//code you want to happen if your word is found
}
Also in your current code, the if statement doesnt actually do anything since you end it with a semicolon and not {} or leave it blank if its one line. You can see an example of the if statement as well
Below is a link to find and iterators
http://www.cplusplus.com/reference/algorithm/find/
That find function will find some element of the negvibe array that is equal to userfeeling. If you are checking whether any element of negvibe is a substring of userfeeling, you should loop through negvibe and use the std::string::find method.
bool found_negvibe = false;
for (int i = 0; i < sizeof(negvibe) / sizeof(*negvibe); i++) {
found_negvibe = found_negvibe || userfeeling.find(negvibe[i]) != string::npos;
}
Also, you don't need to specify the size of the negvibe array, you can write this:
string negvibe[] = {"bad","terrible","lousy","meh"};
One more thing, you might prefer to use a std::vector over an array, if only because c++'s faculties for getting the size of a vector are slightly more succinct than those for getting the size of an array.
vector negvibe = {"bad","terrible","lousy","meh"};
bool found_negvibe = false;
for (int i = 0; i < negvibe.size(); i++) {
found_negvibe = found_negvibe || userfeeling.find(negvibe[i]) != string::npos;
}

Why is replacing an element of a vector so slow?

I notice that amending (or replacing) an element in a large vector is consuming a lot of time when the vector is getting bigger, even when the element's place in the vector is known.
Is there an explanaition for this?
I use an unsorted set as an index. The code first tries to find the element in the set with set.find(). If the element not present in the set the code insert it at the end of the set and at the same time pushes it at the end of the vector.
If the element is found on position "x" of the set the data in the vector is replaced by using:
vector.at(x)=vector[x]+element.
When I skip the vector part and only insert the element in the set the code easily processes 95 million elements in less then 2 minutes. But when I add the vector part to it the code keeps on running for hours.
The file I'm importing is a semicolumn separated text, with below structure
2161182;Jutfaseweg;footway;no;7740068,13877901
2953564;Timorkade;cycleway;no;7785429,368846814,582743212,582743202,582743213,582743203,582743214,582743206,582743210,45200603
Each line represents a way. The ID's in the last element are waypoints of that particular way. Each element has a righthand neighbour, unless it is the last element of the way and based on the 4th element ("yes" or "no", meaning oneway or not), also a lefthand neighbour, unless it is the first element of the way.
Below is the code as requested
#include <windows.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <cstring>
#include <cstdint>
#include <cstdio>
#include <set>
#include <vector>
using namespace std;
set<string>PresentStreet;
set<int>PresentNode;
vector<string>NeighBours;
string line1;
void split(const string& s, char c,
vector<string>& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
int main(int argc, char *argv[]) {
ifstream myfile ("filename.txt");
int CounterLine=1;
while ( getline (myfile,line1) ) {
string s1=line1;
vector<string> v1;
split(line1, ';', v1);
PresentStreet.insert(v1[2]);
vector<string> v2;
split(v1[4], ',', v2);
for (int t=0;t<v2.size();t++) {
auto search = PresentNode.find(atoi(v2[t].c_str()));
if(search == PresentNode.end()) {
string Neighbours="";
if(v1[3].find("no")!=std::string::npos&&t>0) {
Neighbours=Neighbours+v2[t-1]+",";
}
if(t<v2.size()-1) {
Neighbours=Neighbours+v2[t+1]+",";
}
stringstream ss;
ss<<CounterLine;
stringstream ss2;
ss2<<v2[t];
PresentNode.insert(atoi(v2[t].c_str()));
NeighBours.push_back(Neighbours);
}else{
int nPosition = distance (PresentNode.begin (), search);
string Neighbours=NeighBours[nPosition];
if(v1[3].find("no")!=std::string::npos&&t>0) {
Neighbours=Neighbours+v2[t-1]+",";
}
if(t<v2.size()-1) {
Neighbours=Neighbours+v2[t+1]+",";
}
NeighBours.at(nPosition)=Neighbours;
}
}CounterLine++;
}
}

How to move file pointer back by one integer?

Say I have a file containing integers in the form
1 57 97 100 27 86 ...
Say that I have a input file stream fin and I try to read the integers from the file.
ifstream fin("test.txt");
int val;
fin>>val;
Now I am doing this action in a while loop where at one period of time, I want to move my file pointer exactly one integer back. That is if my file pointer is about to read the integer 27 when I do fin>>val, I want to move the file pointer such that it can read the integer 100 when I do fin>>val. I know we can use fin.seekg() but I have used it only to move the file pointers by characters, not by integers.
Probably this is a naive question. But can someone please help me out?
You can use tellg after each read to save the pointer to be used later on with a seekg.
You could also take the implementation of << and modify it with a function that also returns the number of characters you have advanced each time. Where to find the source code of operator<< is not something where I could easily help you with.
In your case it is not an integer, but a text representing a number. Because of this you will have to move backward character by character until you find a non-digit one (!isdigit(c)).
As one of the commenters below pointed out, you may also pay attention to a the 'minus' sign in case your numbers can be negative.
first argument is the file name, second argument is the numbers index, program displays the number at the index and then displays the previous number (counting from zero)
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
int main(int argc, char *argv[]){
if(argc != 3){
std::cout<<"argument error!\n";
return 1;
}
std::ifstream read;
read.open(argv[1],std::ios::app);
if( read.is_open() ){
std::vector<int> numbers;
int temp;
while(read >> temp){
numbers.push_back(temp);
}
std::cout<<"1) "<<numbers[atoi(argv[2])]<<"\n2) "<<numbers[atoi(argv[2]-1)]<<std::endl;
read.close();
}else {
std::cout<<"file open error!\n";
return 2;
}
return 0;
}
Try the following:
#include <iostream>
#include <fstream>
#include <locale>
int main()
{
std::ifstream fin("test.txt");
int val;
bool back = false;
for (int i = 0; fin >> val;)
{
if (!back && val == 27)
{
while (i++ < 2)
while (!std::isspace(fin.unget().rdbuf()->sgetc()));
back = true;
}
}
}
You could take a look at istream::unget()
#include <fstream>
#include <iostream>
int main()
{
ifstrem file("fileName.txt");
char var=file.get()://now this will move file pointer one time forward
/* Seekg(n,position) accept two arguments.The number of bits and position
from where to move the file pointer
if value of n is negative then file pointer will move back.
*/
file.seekg(-1,ios::cur);//to move the file back by one bit from current position
retur
n 0;
}

Finding all occurrences of a character in a string

I have comma delimited strings I need to pull values from. The problem is these strings will never be a fixed size. So I decided to iterate through the groups of commas and read what is in between. In order to do that I made a function that returns every occurrence's position in a sample string.
Is this a smart way to do it? Is this considered bad code?
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results = findLocation(test,findIt);
return 0;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
As currently written, this will simply return a vector containing the int representations of the characters themselves, not their positions, which is what you really want, if I read your question correctly.
Replace this line:
characterLocations.push_back(sample[i]);
with this line:
characterLocations.push_back(i);
And that should give you the vector you want.
If I were reviewing this, I would see this and assume that what you're really trying to do is tokenize a string, and there's already good ways to do that.
Best way I've seen to do this is with boost::tokenizer. It lets you specify how the string is delimited and then gives you a nice iterator interface to iterate through each value.
using namespace boost;
string sample = "Hello,My,Name,Is,Doug";
escaped_list_seperator<char> sep("" /*escape char*/, ","/*seperator*/, "" /*quotes*/)
tokenizer<escaped_list_seperator<char> > myTokens(sample, sep)
//iterate through the contents
for (tokenizer<escaped_list_seperator<char>>::iterator iter = myTokens.begin();
iter != myTokens.end();
++iter)
{
std::cout << *iter << std::endl;
}
Output:
Hello
My
Name
Is
Doug
Edit If you don't want a dependency on boost, you can also use getline with an istringstream as in this answer. To copy somewhat from that answer:
std::string str = "Hello,My,Name,Is,Doug";
std::istringstream stream(str);
std::string tok1;
while (stream)
{
std::getline(stream, tok1, ',');
std::cout << tok1 << std::endl;
}
Output:
Hello
My
Name
Is
Doug
This may not be directly what you're asking but I think it gets at your overall problem you're trying to solve.
Looks good to me too, one comment is with the naming of your variables and types. You call the vector you are going to return characterLocations which is of type int when really you are pushing back the character itself (which is type char) not its location. I am not sure what the greater application is for, but I think it would make more sense to pass back the locations. Or do a more cookie cutter string tokenize.
Well if your purpose is to find the indices of occurrences the following code will be more efficient as in c++ giving objects as parameters causes the objects to be copied which is insecure and also less efficient. Especially returning a vector is the worst possible practice in this case that's why giving it as a argument reference will be much better.
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results;
findLocation(test,findIt, results);
return 0;
}
void findLocation(const string& sample, const char findIt, vector<int>& resultList)
{
const int sz = sample.size();
for(int i =0; i < sz; i++)
{
if(sample[i] == findIt)
{
resultList.push_back(i);
}
}
}
How smart it is also depends on what you do with those subtstrings delimited with commas. In some cases it may be better (e.g. faster, with smaller memory requirements) to avoid searching and splitting and just parse and process the string at the same time, possibly using a state machine.