I'm using getline() to parse coordinate lines from a kml file into a vector.
The relevant part of the kml file looks like this (replaced numbers with x)...
<coordinates>
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
-xxxxxxxxx,xxxxxxxxx,0
</coordinates>
When using getline() to print the kml file line by line it does it just fine so I figured something like this would work to parse coordinates into a vector...
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
vector <string> coordinates;
int main() {
fstream inputFile("Fish.kml", fstream::in);
string str;
bool running = true;
int counter = 0;
while (running) {
getline(inputFile, str, '\0');
if (str == " <coordinates>") {
counter++;
}
if (counter > 0 && str != " </coordinates>") {
coordinates.push_back(str);
}
if (counter > 0 && str == " </coordinates>") {
counter = -1;
running = false;
}
}
inputFile.close();
for (int i = 0; i < coordinates.size(); i++) {
cout << coordinates[i] << "\n";
}
return 0;
}
My thinking was to use if statements to check whether the getline() function is about to read the coordinates by checking if the line, "coordinates", has been read or not. If it has it will increase the counter to above zero that way in the next loop the rest of the program knows to start logging coordinates. Same thinking applies to stopping the code by checking to see if the line "/coordinates" has been read. It's all I could think of with my current knowledge, but obviously I must be missing something important because...
When I compile and run I don't get any errors but the program doesn't do anything. This is what it looks like, It does nothing, my computer fans kick on and I have to cancel the process...
irectory>test.exe
^C
Any ideas what is going on here?
Thank you!
Update:
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
vector <string> coordinates;
int main() {
fstream inputFile("Fish.kml", fstream::in);
string str;
bool running = true;
int counter = 0;
while (getline(inputFile, str, '\0')) {
if (str == " <coordinates>") {
counter++;
}
if (counter > 0 && str != " </coordinates>") {
coordinates.push_back(str);
}
if (counter > 0 && str == " </coordinates>") {
counter = -1;
inputFile.close();
}
}
for (int i = 0; i < coordinates.size(); i++) {
cout << coordinates[i] << "\n";
}
return 0;
}
I updated the code above as suggested and it does not get stuck while executing anymore. But it does not print the vector back. I'm not sure if it is failing to record the lines of coordinates or if I didn't print it properly.
replace while(running) with while(getline(inputFile, str) and remove running variable as it is no longer needed.
And also
if (str == "<coordinates>") {
counter++;
}
if (counter > 0 && str != "</coordinates>") {
coordinates.push_back(str);
}
if (counter > 0 && str == "</coordinates>") {
counter = -1;
}
Hopefully the following code would help you a little bit. I worte it myself. It only reads the first coordinates part.
//
// Created by albert on 4/1/22.
//
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
vector<float> split(string s, string del) {
int start = 0;
int end = s.find(del, start);
vector<float> ret;
while (end != string::npos) {
string substr = s.substr(start, end - start);
if (!substr.empty())
ret.push_back(stof(substr));
start = end + del.size();
end = s.find(del, start);
}
string substr = s.substr(start, end - start);
if (!substr.empty())
ret.push_back(stof(substr));
return ret;
}
int main() {
fstream istream;
istream.open("map.kml", fstream::in);
vector<vector<float>> coordinates;
bool flag = false;
if (istream.is_open()) {
cout << "file is open" << endl;
string str;
while (getline(istream, str, '\n')) {
if (str == " <coordinates>")
flag = true;
else if (str == " </coordinates>") {
flag = false;
break;
} else if (flag)
coordinates.push_back(split(str, string(1, ',')));
}
}
istream.close();
for (int i = 0; i < coordinates.size(); i++) {
cout << coordinates[i][0] << " " << coordinates[i][1] << " " << coordinates[i][2] << "\n";
}
cout << coordinates.size() << endl;
return 0;
}
I'm a beginner in c++ and required to write a c++ program to read and print a csv file like this.
DateTime,value1,value2
12/07/16 13:00,3.60,50000
14/07/16 20:00,4.55,3000
May I know how can I proceed with the programming?
I manage to get the date only via a simple multimap code.
I spent some time to make almost (read notice at the end) exact solution for you.
I assume that your program is a console application that receives the original csv-file name as a command line argument.
So see the following code and make required changes if you like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
std::vector<std::string> getLineFromCSV(std::istream& str, std::map<int, int>& widthMap)
{
std::vector<std::string> result;
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
int cellCnt = 0;
while (std::getline(lineStream, cell, ','))
{
result.push_back(cell);
int width = cell.length();
if (width > widthMap[cellCnt])
widthMap[cellCnt] = width;
cellCnt++;
}
return result;
}
int main(int argc, char * argv[])
{
std::vector<std::vector<std::string>> result; // table with data
std::map<int, int> columnWidths; // map to store maximum length (value) of a string in the column (key)
std::ifstream inpfile;
// check file name in the argv[1]
if (argc > 1)
{
inpfile.open(argv[1]);
if (!inpfile.is_open())
{
std::cout << "File " << argv[1] << " cannot be read!" << std::endl;
return 1;
}
}
else
{
std::cout << "Run progran as: " << argv[0] << " input_file.csv" << std::endl;
return 2;
}
// read from file stream line by line
while (inpfile.good())
{
result.push_back(getLineFromCSV(inpfile, columnWidths));
}
// close the file
inpfile.close();
// output the results
std::cout << "Content of the file:" << std::endl;
for (std::vector<std::vector<std::string>>::iterator i = result.begin(); i != result.end(); i++)
{
int rawLen = i->size();
for (int j = 0; j < rawLen; j++)
{
std::cout.width(columnWidths[j]);
std::cout << (*i)[j] << " | ";
}
std::cout << std::endl;
}
return 0;
}
NOTE: Your task is just to replace a vector of vectors (type std::vector<std::vector<std::string>> that are used for result) to a multimap (I hope you understand what should be a key in your solution)
Of course, there are lots of possible solutions for that task (if you open this question and look through the answers you will understand this).
First of all, I propose to consider the following example and to try make your task in the simplest way:
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string str = "12/07/16 13:00,3.60,50000";
stringstream ss(str);
vector<string> singleRow;
char ch;
string s = "";
while (ss >> ch)
{
s += ch;
if (ss.peek() == ',' || ss.peek() == EOF )
{
ss.ignore();
singleRow.push_back(s);
s.clear();
}
}
for (vector<string>::iterator i = singleRow.begin(); i != singleRow.end(); i++)
cout << *i << endl;
return 0;
}
I think it can be useful for you.
My code works fine on codeblocks compiler on my computer but when I upload it to an online editor I get an Segmentation fault error and I don't know why.
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) {
ifstream stream(argv[1]);
char line[1000];
int x,last=-1;
while (stream>>line)
{
x = atoi(strtok(line,","));
cout<<x;
last=x;
while(x=atoi(strtok(NULL,",")))
{
if(x!=last)
{
cout<<","<<x;
last=x;
}
}
cout<<endl;
}
return 0;
}
You are given a sorted list of numbers with duplicates. Print out the sorted list with duplicates removed.
And this is the input
6,7,8,9,9,10,11,12,13,14,15
11,12,13,14,15,16,17,18,19,20
2,2,2,2,2
10,11,12,13,14,15,16,16,17
13,14,14,15,16,17,17,17,18
15,16,17,17,18,18,18,18,19,19,20
2,3,4,5,5
13,14,15,16,17
10,11,12,13,14,15,15,15,15,16,16,16
12,13,14,15,16,17,17,18
5,6,7,8,9,10,11
14,14,14,15,15,16,17,17,18,19,19,20,21,22
13,14,15,16,16,17,17,18
15,16,17,18,19,20,21,21,21,21,22,22
6,6,6,7,8,9,10,11,11,11,12,12,13
12,12,13,14,15,15,16,17,17,18,19,19,20,21
8,9,9,9,10,10,11,12,13,13,14,15
12,13,14,15,16,17,18
1,1,1,2,2,3,3,4,4
1,2,3,4
Since you're asking us to guess, let's start at the top ....
The code doesn't check that argv[1] is valid. If not, then you just dereferenced a null-pointer, and that caused your segmentation fault.
Does your "online editor" pass parameters? I suggest checking argc > 1.
Next, your code looks like it will pass a null pointer to atoi at the end of every line. That's another segmentation fault.
You are calling atoi with the result of strtok.
If strtok doesn't find anything it returns a null pointer.
This is the case at the end of the line.
So you are passing a null pointer to atoi which then leads to a crash.
Using your example this should work:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
int main(int argc, char *argv[])
{
ifstream stream(argv[1]);
char line[1000];
char* ln;
char* num;
int x;
int last;
while (stream >> line)
{
ln = line;
last = -1;
while (num = strtok(ln, ","))
{
x = atoi(num);
if (x != last)
{
if(last != -1) cout << "," << x;
else cout << x;
last = x;
}
ln = NULL;
}
cout << endl;
}
return 0;
}
EDIT: Another solution with checking for valid paramters and w/o strtok and atoi:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
int main(int argc, char *argv[])
{
if (argc < 2) {
cout << "Usage: " << argv[0] << " <file>";
return 1;
}
ifstream stream(argv[1]);
if (!stream.is_open())
{
cout << "Failed to open file \"" << argv[1] << "\"";
return 2;
}
char line[1000];
while (stream >> line)
{
int last = -1;
int x = 0;
for (char* pos = line; pos < line + strlen(line); pos++)
{
if (*pos >= '0' && *pos <= '9')
{
x = (x * 10) + (*pos - '0');
}
else
{
if (last != x)
{
if (last != -1) {
cout << ',';
}
cout << x;
last = x;
}
x = 0;
}
}
cout << endl;
}
return 0;
}
the point of my program is to write the numbers 1 - 1,000,000 to a text file, generate a random number between 1 and 1,000,000, search for that line in the text file, take the value, and square it (this is just an exercise for me, it has no practical application). The problem is that whenever I run it, the value remains the same, but the rand() function is seeded by time(0). I suspect that it's a garbage value but I don't know where it's coming from (I have no experience with GDB or any other standalone debuggers). Here's my source code:
#include <fstream>
#include <ctime>
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(int argc, char** argv){
ofstream file("log.txt", ios::app);
ofstream programLog("programlog.dat", ios::app);
cout << "Test Start" << endl;
programLog << "Test Start" << endl;
cout << "Log file created" << endl;
programLog << "Log file created" << endl;
ifstream readFile("log.txt");
int foundNum;
std::string line = "";
unsigned int loopCount = 1000000;
unsigned int numToSearch;
const unsigned short min = 1;
const int max = 1000000;
unsigned int randomLine = 0;
for(int i = 0; i <= loopCount; i++){
file << i << endl;
}
//select random line
srand((unsigned)time(0));
while(!(randomLine > min) && !(randomLine < max)){
randomLine = (unsigned)rand();
programLog << randomLine;
int newlines = 0;
//size_t found;
while(getline(readFile, line)){
if(line.find("\n") != string::npos)
newlines++;
if(newlines == randomLine)
numToSearch = atoi(line.c_str());
}
}
programLog << "Random line selected" << endl;
//read line
while(std::getline(readFile,line)){
if(atoi(line.c_str()) == numToSearch){
foundNum = numToSearch;
break;
}
else
continue;
}
//square it
const unsigned int squared = foundNum*foundNum;
programLog << squared;
readFile.close(); //end read
file.close(); //end log
programLog.close(); //end programlog
return 0;
}
You never enter the while loop as you are using:
while(!(randomLine > min) && !(randomLine < max))
while immediately evaluates to false. You should use:
while(randomLine < min || randomLine > max)
Also, why do all your variables have different types? This could lead to unintended errors. You should change them to have the same type.
randomLineis initialized to 0, and still has that value once it reaches the while, so the loop body never executes.