Assertion failure when writing to a text file using ofstream - c++

I am trying to write some string data to a .txt file that i read from the user but after doing so, the program shuts down instead of continuing and when i check the results inside the .txt file i see some part of the data and then some gibberish, followed by an assertion failure error! Here's the code:
#include "std_lib_facilities.h"
#include <fstream>
using namespace std;
using std::ofstream;
void beginProcess();
string promptForInput();
void writeDataToFile(vector<string>);
string fileName = "links.txt";
ofstream ofs(fileName.c_str(),std::ofstream::out);
int main() {
// ofs.open(fileName.c_str(),std::ofstream::out | std::ofstream::app);
beginProcess();
return 0;
}
void beginProcess() {
vector<string> links;
string result = promptForInput();
while(result == "Y") {
for(int i=0;i <= 5;i++) {
string link = "";
cout << "Paste the link skill #" << i+1 << " below: " << '\n';
cin >> link;
links.push_back(link);
}
writeDataToFile(links);
links.clear(); // erases all of the vector's elements, leaving it with a size of 0
result = promptForInput();
}
std::cout << "Thanks for using the program!" << '\n';
}
string promptForInput() {
string input = "";
std::cout << "Would you like to start/continue the process(Y/N)?" << '\n';
std::cin >> input;
return input;
}
void writeDataToFile(vector<string> links) {
if(!ofs) {
error("Error writing to file!");
} else {
ofs << "new ArrayList<>(Arrays.AsList(" << links[0] << ',' << links[1] << ',' << links[2] << ',' << links[3] << ',' << links[4] << ',' << links[5] << ',' << links[6] << ',' << "));\n";
}
}
The problem lies probably somewhere in the ofstream writing procedure but i can't figure it out. Any ideas?

You seem to be filling a vector of 6 elemenents, with indices 0-5, however in your writeDataToFile function are dereferencing links[6] which is out of bounds of your original vector.
Another thing which is unrelated to your problem, but is good practice:
void writeDataToFile(vector<string> links)
is declaring a function which performs a copy of your vector. Unless you want to specifically copy your input vector, you most probably want to pass a const reference, like tso:
void writeDataToFile(const vector<string>& links)

Related

Problems printing from map<string, struct> in C++

I'm learnig C++. Here is my problem: I'm trying to read data from a text file and save it to a map<string, struct> and then have it print out all the keys from the map preferably in alphabetical order. The data has 2 strigns and a float. I can't get this to print even after having tried many different solutions.
Heres what I've got so far:
Here is my struct:
struct category
{
std::string tram_stop;
float dist;
};
using Tram = std::map<std::string, std::vector<category>>;
Here is where I try to save the data to the map.
void store(Tram& tram, std::vector<std::string>& tram_data)
{
if (tram.find (tram_data.at (0)) == tram.end ())
{
tram[tram_data.at (0)] = {};
}
else
{
tram.at (tram_data.at (0)).push_back (category {tram_data.at (1), std::stof(tram_data.at(2))});
}
}
And here is main().
int main()
{
Tram tram;
print_rasse();
// Ask input filename.
std::string filename;
std::cout << "Give a name for input file: ";
std::cin >> filename;
// Read input file.
std::ifstream file_in;
file_in.open (filename);
if (!file_in.is_open ())
{
std::cout << INVALID_FILE << std::endl;
return EXIT_FAILURE;
}
std::vector<std::string> tram_data;
if (file_in.is_open())
{
std::string line;
while( std::getline(file_in,line) )
{
std::stringstream ss(line);
std::string tram_line, tram_stop, distance;
std::getline(ss,tram_line,';'); //std::cout<< ""<<tram_line <<" ";
std::getline(ss,tram_stop,';'); //std::cout<<" "<<tram_stop<<" ";
std::getline(ss,distance); //std::cout<<" "<<distance<< " ";
if (tram_line != "" && tram_stop != "")
{
tram_data.push_back (tram_line);
tram_data.push_back (tram_stop);
tram_data.push_back (distance);
//std::cout << tram_line << " " << distance << std::endl;
}
else
{
std::cout << INVALID_FORMAT << std::endl;
return EXIT_FAILURE;
}
}
file_in.close ();
store(tram, tram_data);
}
This is the part I think doesn't work. Tried different iterators too.
if (upper_com == "LINES")
{
std::cout << "All tramlines in alphabetical order:" << std::endl;
for (auto& item : tram)
{
std::cout << item.first << std::endl;
}
}
Your implementation of store will create a vector for the first item added for a particular tram_data[0] value, but will not add anything to the vector. This results in losing that first item, and can result in no output because of the empty vectors.
That function can be simplified:
void store(Tram& tram, std::vector<std::string>& tram_data)
{
if (tram_data.size() < 3) throw std::out_of_range();
tram[tram_data[0]].emplace_back(tram_data[1], std::stof(tram_data[2]));
}
You don't need to use at with tram because you want to create the entry if it doesn't exist. at with tram_data will result in an exception being thrown if there are fewer than three elements in tram_data, so that check has been moved outside all the accesses to the vector.

Undeclared Identifier in my function call (C++)

I am a new programmer working in C++, I am trying to make a program that will import information from a file to an output file and then I'm going to do a search algorithm on the data. I am trying to use a structure of data and import that into an array and then call it in the main program.
For some reason I can't, for the life of me, get my function call to work; I keep getting an undeclared identifier error on inputFile in my function call in the main program. I realize I'm probably doing something fundamentally wrong, so I would really appreciate any help that can be given.
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
const int MAX_LOG_SIZE = 7584;
const string LOGFILE ="crimes.dat";
const string OUTPUT_FILE ="crimesorted.log";
// Structure of strings based on info from crimes.dat
struct CrimeInfo
{
string Crimedescr;
string Date;
string Time;
string Address;
string Grid;
string Latitude;
string Longitude;
};
CrimeInfo crimeList [MAX_LOG_SIZE];
void openInputFile(ifstream& inputFile, string inputFilename)
// here we open the input file crimes.dat
{
inputFile.open(inputFilename.c_str());
while (inputFile.fail())
{
cout << "Failed to open input file: " << inputFilename << ".\n";
exit(1);
}
};
void getLogEntry(ifstream &LOGFILE, CrimeInfo &entry)
{
getline(LOGFILE, entry.Date);
getline(LOGFILE, entry.Time);
getline(LOGFILE, entry.Address);
getline(LOGFILE, entry.Grid);
getline(LOGFILE, entry.Crimedescr);
getline(LOGFILE, entry.Latitude);
getline(LOGFILE, entry.Longitude);
}
/* opens an output file */
void openOutputFile(ofstream& outputFile, string outputFilename)
{
outputFile.open(outputFilename.c_str());
if (outputFile.fail())
{
cout << "Failed to open output file: " << outputFilename << ".\n";
exit(2);
}
}
void outputLogFile(string outputFilename, CrimeInfo arr[], int size)
{
// open output files
ofstream outputLogFile;
openOutputFile(outputLogFile, outputFilename);
// output the crime file
outputLogFile << "\nCrime log sort ^^:\n\n";
for (int i = 0; i < size; i++)
{
outputLogFile << arr[i].Date << " ";
outputLogFile << arr[i].Address << " (";
outputLogFile << arr[i].Longitude << " ";
outputLogFile << arr[i].Latitude << " ";
outputLogFile << arr[i].Time << " ";
outputLogFile << arr[i].Grid << " ";
outputLogFile << arr[i].Crimedescr << "";
outputLogFile << endl;
}
outputLogFile.close();
}
int main()
{
outputLogFile(OUTPUT_FILE, crimeList, MAX_LOG_SIZE);
for (int i =0; i < MAX_LOG_SIZE; i++)
getLogEntry(inputFile, crimeList[i].Date);
}
There are a lot of problems with your code. To help you out, I went through your code and left a lot of my own comments to tell you some suggestions I had; to make it easy, I deleted your comments so there's no confusion on what was yours and what I put there.
Here are some things I noticed in your code:
using namespace std is generally considered a very bad practice. Instead, just specify the namespace (e.g. std::string instead of just string).
You declared LOGFILE as a string at the top of your program, but then tried to use it as an ifstream& in the function getLogEntry.
Your main method is out of order. I'm assuming you want to load some data into the program from a file and then output that data to another file. The way you have it in your main method is, first, you output information you don't have yet and, second, import information but don't do anything with it.
You have a LOT of functions. As a general rule of thumb, don't make a whole function for opening a file, then a separate one for using it, then a separate one for closing it. There are a lot of big reasons why not to do this. The biggest reasons are that your program becomes very difficult to follow, and no one else will be able to use your code. In real-world applications, your code is only 20% for the computer and 80% for other programmers.
There are various formatting errors and such.
So, here is your original code with my comments...
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib> // Unneeded since other headers here already include this
#include <fstream>
using namespace std; // NEVER globally use the entire standard namespace!
const int MAX_LOG_SIZE = 7584; // Can be declared 'constexpr'
const string LOGFILE ="crimes.dat";
const string OUTPUT_FILE ="crimesorted.log";
/*
NOTE:
> It often looks a lot cleaner to have a header part of your code
and then define your functions seperately. This is good practice
for when you need to start using header files with big projects
*/
struct CrimeInfo
{ // Can declare all variables by only listing type once if they're all the same type
string Crimedescr;
string Date;
string Time;
string Address;
string Grid;
string Latitude;
string Longitude;
};
CrimeInfo crimeList [MAX_LOG_SIZE]; // This should be in 'main()'
/*
This should not be its own function.
Making too many function can make things look a bit confusing.
Here, this is only 4 lines of code, so you shouldn't be making
an entire function for it.
*/
void openInputFile(ifstream& inputFile, string inputFilename)
{
inputFile.open(inputFilename.c_str());
while (inputFile.fail())
{
cout << "Failed to open input file: " << inputFilename << ".\n";
exit(1);
}
};
/*
This should also just be written out where its used. There's
no need to make a whole function for a task like this.
ERROR HERE:
> LOGFILE is NOT an std::ifstream! It is a std::string!
*/
void getLogEntry(ifstream &LOGFILE, CrimeInfo &entry)
{
getline(LOGFILE, entry.Date);
getline(LOGFILE, entry.Time);
getline(LOGFILE, entry.Address);
getline(LOGFILE, entry.Grid);
getline(LOGFILE, entry.Crimedescr);
getline(LOGFILE, entry.Latitude);
getline(LOGFILE, entry.Longitude);
}
/*
This should not be its own function.
Making too many function can make things look a bit confusing.
Here, this is only 4 lines of code, so you shouldn't be making
an entire function for it.
*/
void openOutputFile(ofstream& outputFile, string outputFilename)
{
outputFile.open(outputFilename.c_str());
if (outputFile.fail())
{
cout << "Failed to open output file: " << outputFilename << ".\n";
exit(2);
}
}
// It's a good idea to use some sort of documentation style for functions
void outputLogFile(
// Declare variables const when they aren't modified
/* (const) */ string outputFilename,
/* (const) */ CrimeInfo arr[],
/* (const) */ int size)
{
ofstream outputLogFile;
openOutputFile(outputLogFile, outputFilename); // Just write out the code
outputLogFile << "\nCrime log sort ^^:\n\n";
for (int i = 0; i < size; i++)
{
/*
You only need to declare the name of the stream one time
e.g.
outputLogFile << thing1 << thing2
<< thing3 << thing4 << thing5
<< thing6
<< endl;
*/
outputLogFile << arr[i].Date << " ";
outputLogFile << arr[i].Address << " (";
outputLogFile << arr[i].Longitude << " ";
outputLogFile << arr[i].Latitude << " ";
outputLogFile << arr[i].Time << " ";
outputLogFile << arr[i].Grid << " ";
outputLogFile << arr[i].Crimedescr << ""; // Empty quotes not needed here
outputLogFile << endl;
}
outputLogFile.close();
}
int main()
{
// What data are you outputting?
outputLogFile(OUTPUT_FILE, crimeList, MAX_LOG_SIZE);
// Are you trying to load the data you just outputted?
for (int i =0; i < MAX_LOG_SIZE; i++)
{ // I added these braces, but it's a good idea to always have braces
// You have not declared 'inputFile' anywhere
getLogEntry(inputFile, crimeList[i].Date);
}
}
Instead of leaving you to have to figure all that out on your own (I know how frustrating that can be), I went ahead and wrote your program how I'd do it. I tried to put comments in a lot of places to make it easy to follow along with. If you have any questions about it, feel free to ask me.
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
/*
If you're using C++17, the lines below can just become one line:
using std::cin, std::cout, std::endl, std::ifstream,
std::ofstream, std::string, std::getline;
*/
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::string;
constexpr int MAX_LOG_SIZE = 7584;
const string LOGFILE_NAME = "crimes.dat";
// I'm assuming: inputFile ^^^
// outputFile vvv
const string OUTPUT_FILE_NAME = "crimesorted.log";
/*
NOTE: If you're trying to export data to "crimesorted.log"
and then load it back into the program through "crimes.dat",
that will be a problem. I say this because the main method
in your original code, this is the order you had it in.
*/
// [BEGIN] Function Prototypes
// Structure of strings based on info from crimes.dat
struct CrimeInfo
{
string Crimedescr, Date, Time, Address,
Grid, Latitude, Longitude;
};
/** (This is JavaDoc-style documentation)
[Purpose of function here]
#param outputFile [Describe paramater here]
#param arr[] [Describe parameter here]
#param size_of_arr Size of 'arr[]'
*/
void outputLogFile(
ofstream& outputFile, // Changed to 'std::ofstream&' because I declare this in 'main()'
const CrimeInfo arr[],
const int size_of_arr);
// [END] Function Prototypes
int main()
{
// Create std::ifstream and open a file
ifstream file_to_load;
file_to_load.open(LOGFILE_NAME);
// Constructing and using 'crimeList' here allows the size to be known in
// this scope. However, if it's passed to a function, it's passed as a pointer
CrimeInfo crimeList[MAX_LOG_SIZE];
// Check if file was open and do stuff with it
if (file_to_load.is_open())
{ // File was opened
for (int i = 0; i < MAX_LOG_SIZE; i++)
{
getline(file_to_load, crimeList[i].Date);
getline(file_to_load, crimeList[i].Time);
getline(file_to_load, crimeList[i].Address);
getline(file_to_load, crimeList[i].Grid);
getline(file_to_load, crimeList[i].Crimedescr);
getline(file_to_load, crimeList[i].Latitude);
getline(file_to_load, crimeList[i].Longitude);
}
file_to_load.close(); // Close file
}
else
{ // File could not be
cout << "Could not open file: " << LOGFILE_NAME << endl;
return 1;
}
// Create std::ofstream and output the log
ofstream outputFile;
outputFile.open(OUTPUT_FILE_NAME);
// Check if 'outputFile' opened OUTPUT_FILE_NAME successfully
if(outputFile.is_open())
{ // File was opened
outputLogFile(outputFile, crimeList, MAX_LOG_SIZE);
outputFile.close();
}
else
{ // File could not be opened
cout << "Could not open file: " << OUTPUT_FILE_NAME << endl;
return 1;
}
}
// Function definition for outputLogFile()
void outputLogFile(
ofstream &outputFile,
const CrimeInfo arr[],
const int size_of_arr)
{
outputFile << "\nCrime log sort ^^:\n\n";
for (int i = 0; i < size_of_arr; i++)
{
outputFile
<< arr[i].Date << '\n' // Newlines may look better than spaces here
<< arr[i].Address << " ("
<< arr[i].Longitude << ", "
<< arr[i].Latitude << ")\n"
<< arr[i].Time << '\n'
<< arr[i].Grid << '\n'
<< arr[i].Crimedescr
<< endl;
}
}

Trying to code Graph in c++, getting bad_alloc some of the time

I'm new to c++ after learning basic Object Oriented Programming in Java so I'm having a difficult time grasping memory deallocation. The assignment was to create a Weighted Directed Graph...
I'm getting the error: "terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc" when I run certain inputs through my code, and I'm having a difficult time figuring out what is causing it.
I googled the error and found that it was a memory problem, so I attempted to go through my code and try to find any leaks, but I am not sure where they are. Most posts are talking about pointers, which I do not tend to implement because I am unfamiliar with them. Thank you for your time!
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <iterator>
#include <map>
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
class WDGraph {
private:
map<string,map<string,int>> edges;
vector<string> verts;
list<string> leaves;
list<string> roots;
list<string> selfEdges;
public:
list<string> getRoots() { return roots; }
list<string> getLeaves() { return leaves; }
void addVert(string key) {
verts.push_back(key);
}
void link(string start, string dest, int cost) {
edges[start].insert(make_pair(dest,cost));
if (!containsLeaf(dest) && !containsVert(dest))
leaves.push_back(dest);
if (!containsRoot(start) && !containsVert(start))
roots.push_back(start);
if (start == dest)
selfEdges.push_back(start);
roots.remove(dest);
leaves.remove(start);
}
bool containsVert(string key) {
for (int i=0; i < verts.size(); i++) {
if (key == verts[i]) {
return true;
}
}
return false;
}
bool containsRoot(string key) {
bool found = (find(roots.begin(), roots.end(), key) != roots.end());
return found;
}
bool containsLeaf(string key) {
bool found = (find(leaves.begin(), leaves.end(), key) != leaves.end());
return found;
}
WDGraph() { }
void printWDG() {
cout << "Printing Weighted Directed Graph." << endl;
for (auto itr1 = edges.begin(); itr1 != edges.end(); ++itr1) {
for (auto itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2) {
if (itr2->first == "null" && containsRoot(itr1->first)) {
cout << "[" << itr1->first << "]";
}
else if (itr2->first != "null")
cout << "[" << itr1->first << " -> ";
cout << itr2->first << ", " << itr2->second << "] ";
}
cout << "" << endl;
}
}
void printNumVerts() {
cout << "Total number of vertices: " << verts.size() << endl;
}
void printRoots() {
int num_roots = 0;
cout << "Vertices with zero inbound edges: " << endl;
for (auto itr = roots.begin(); itr != roots.end(); ++itr) {
cout << "[" << *itr << "]" << endl;
num_roots++;
}
if (num_roots == 0) cout << "None" << endl;
}
void printLeaves() {
int num_leaves = 0;
cout << "Vertices with zero outbound edges:" << endl;
for (auto itr = leaves.begin(); itr != leaves.end(); ++itr) {
if (*itr != "null")
cout << "[" << *itr << "]" << endl;
num_leaves++;
}
if (num_leaves == 0) cout << "None" << endl;
}
void printSelfEdges() {
cout << "Vertices with self edges:" << endl;
for (auto itr = selfEdges.begin(); itr != selfEdges.end(); ++itr) {
cout << "[" << *itr << "]" << endl;
}
}
};
int main() {
WDGraph myWDG;
string filePath;
string line;
int weight;
size_t commaPos;
vector<string> sVector;
ifstream dataFile;
// cout << "Please enter the relative path to an input file." << endl;
// getline (cin, filePath);
// cout << "The file path you entered was " << filePath << endl;
// dataFile.open(filePath);
dataFile.open("input.csv"); //test input
while (getline (dataFile, line)) {
commaPos = line.find(',');
//Parse input file into string vector
while (line.length() >= 1) {
if (line.length() == 1) {
sVector.push_back(line);
break;
}
sVector.push_back(line.substr(0,commaPos));
line = line.substr(commaPos+1);
commaPos = line.find(',');
}
//Create vertices depending on number of parameters
if (sVector.size() == 1) {
if (!myWDG.containsVert(sVector[0])) {
myWDG.addVert(sVector[0]);\
}
myWDG.link(sVector[0], "null", 0);
}
if (sVector.size() == 3) {
if (!myWDG.containsVert(sVector[0])) {
myWDG.addVert(sVector[0]);
}
if (!myWDG.containsVert(sVector[1])) {
myWDG.addVert(sVector[1]);
}
weight = stoi(sVector[2]);
myWDG.link(sVector[0], sVector[1], weight);
}
sVector.clear();
}
myWDG.printWDG();
myWDG.printNumVerts();
myWDG.printRoots();
myWDG.printLeaves();
myWDG.printSelfEdges();
}
When my .csv has simple stuff it works as expected, for example:
a,b,1
c,d,2
e
f,f,3
However, if I have stuff like this I get the error "terminate called after throwing an instance of 'std::bad_alloc':
Hello
World,Hello,3
My,Name,4
Is
Nikki,Hello,3
As mentioned by Z E Nir, your line parsing code fails to consume any input if there is no comma "," in the line. You can of course debug your line parsing code, as debugging is a valuable skill to develop anyway.
However, a possible alternative to debugging consists in finding an existing C++ language construct that does what you want to do, and is part of the language library so it is already debugged.
Quite often, what you want to do is "common stuff", so debugging manual code will take more time than finding the appropriate pre-existing language construct, courtesy of your favorite internet search engine and/or stackoverflow itself. And being able to quickly find the language construct is also a very valuable skill.
In your case, function getline() takes an optional delimiter, which is a newline by default, but you can instead have "," as delimiter and so use getline() again, but to parse a single line. It just takes a string object pretending to be a file stream, that is an std::istringstream object.
So you end up with two nested loops, both using getline():
#include <sstream>
while (getline (dataFile, line)) {
std::istringstream iss{line};
std::string token;
while (getline (iss, token, ',')) {
std::cout << "DEBUG TOKEN LEN=" << token.length() << std::endl;
sVector.push_back(token);
}
// go build myWDG
}
That way, you don't have to mess up with lowly details such as the value of your commaPos variable. And the resulting code is easier to understand for another programmer.
Welcome to Stack Overflow.
Heads up: Sorry for the style, but you really have to learn solving those kind of problem on your own. It's called debugging. I'm experienced programmer and yet, my code never run exactly as I thought it will when testing it in the first time. You need to learn how to use a debugger like gdb or the built in debugger in the Visual C++ environment.
Now about your question:
The following code received the variable line with value Hello. There is no , character in line hence line = line.substr(commaPos + 1); return Hello all the time, and since 'Hello' string holds more then one character, you stuck in an infinte loop.
//Parse input file into string vector
while (line.length() >= 1) {
if (line.length() == 1) {
sVector.push_back(line);
break;
}
sVector.push_back(line.substr(0, commaPos));
line = line.substr(commaPos + 1);
commaPos = line.find(',');
}
The problem isn't stop there. Since each iteration over the infinite loop your program executing: sVector.push_back(line.substr(0, commaPos)); you actually allocates more and more memory, till you system won't give any more to this process. That's where you get the bad_alloc exception.
In other words, your error is not about C++, but about poor programing.
Reconsider your program, and think how you want to handle edge-cases like the Hello.
Oh, and never build objects on the stack. I know some places claim its OK to do this in the main function, but belive me its causing a lot of troubles.

Using to upper incorrectly? Working code until I entered toupper

My program worked like it was supposed to until I added the toupper part into my program. I've tried looking at my error code but it's not really helping. The errors are:
no matching function to call
2 arguments expected, one provided
So I know the error is in those two statements in my while loop. What did I do wrong?
I want to make a name like
john brown
go to
John Brown
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
int main(){
string firstname[5];
string lastname[5];
ifstream fin( "data_names.txt" );
if (!fin) {
cout << "There is no file" << endl;
}
int i = 0;
while( i < 5 && (fin >> firstname[i]) && (fin >> lastname[i]) ) {
firstname[0] = toupper(firstname[0]);
lastname[0] = toupper(lastname[0]);
i++;
}
cout << firstname[0] << " " << lastname [0] << endl;
cout << firstname[1] << " " << lastname [1] << endl;
cout << firstname[2] << " " << lastname [2] << endl;
cout << firstname[3] << " " << lastname [3] << endl;
cout << firstname[4] << " " << lastname [4] << endl;
return 0;
}
std::toupper works on individual characters, but you are trying to apply it to strings. Besides adding #include <cctype>, you need to modify your while loop's body:
firstname[i][0] = toupper(firstname[i][0]);
lastname[i][0] = toupper(lastname[i][0]);
i++;
Then it should work as expected. Live demo here
As M.M helpfully pointed out in the comments, you should also check that your strings aren't empty before accessing their first characters, i.e. something like
if (!firstname[i].empty()) firstname[i][0] = toupper(...);
is strongly recommended.
Mind you, you will probably need more sophisticated logic if you get names like McDonald :)
You need ctype.h to get the proper definition for toupper(). It is usually implemented not as a function, but an array mapping.
#include <ctype.h>
The program has several flaws: using a string array instead of a string, not iterating through the string correctly, not declaring but using the C definition of toupper(), not exiting when the file does not exist.
Use this instead:
#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;
int main ()
{
ifstream fin ("data_names.txt");
if (!fin)
{
cerr << "File missing" << endl;
return 1;
}
// not sure if you were trying to process 5 lines or five words per line
// but this will process the entire file
while (!fin.eof())
{
string s;
fin >> s;
for (i = 0; i < s.length(); ++i)
s [i] = toupper (s [i]);
cout << s << endl;
}
return 0;
}

Parsing set of Json files one by one

I am trying to parse Json files using JsonCpp library. but I am facing a problem Which I can not fix it. the code shown below is working perfectly when I am parsing one file but when I added the part which iterates over files in directory the program crashes.
The first function is used to search in a certain directory for Json files and save their names in vector of string (results).
In main function, the program starts by defining the extension required (.json) then calling search function. after that I tried to open each file to parse it.
Finally, Thanks and I really appreciate any kind of help.
#include "jsoncpp.cpp"
#include <stdio.h>
#include "json.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <dirent.h>
#include <vector>
using namespace std;
vector<string> results; // holds search results
// recursive search algorithm
void search(string curr_directory, string extension){
DIR* dir_point = opendir(curr_directory.c_str());
dirent* entry = readdir(dir_point);
while (entry){ // if !entry then end of directory
if (entry->d_type == DT_DIR){ // if entry is a directory
string fname = entry->d_name;
if (fname != "." && fname != "..")
search(entry->d_name, extension); // search through it
}
else if (entry->d_type == DT_REG){ // if entry is a regular file
string fname = entry->d_name; // filename
// if filename's last characters are extension
if (fname.find(extension, (fname.length() - extension.length())) != string::npos)
results.push_back(fname); // add filename to results vector
}
entry = readdir(dir_point);
}
return;
}
//
//
//
//
int main(int argc, char *argv[])
{
// read Files list
string extension; // type of file to search for
extension = "json";
// setup search parameters
string curr_directory = "/Users/ITSGC_Ready2Go/3dMap";
search(curr_directory, extension);
// loop over files
//if (results.size()){
//std::cout << results.size() << " files were found:" << std::endl;
for (unsigned int z = 0; z < results.size(); ++z){ // used unsigned to appease compiler warnings
// Opening the file using ifstream function from fstream library
cout <<results[z].c_str()<<endl;
Json::Value obj;
Json::Reader reader;
ifstream test(results[z].c_str());
//test.open (results[z].c_str(), std::fstream::in );
// Selection objects inside the file
reader.parse(test,obj);
//test >> obj;
// Parsing ID object and returning its value as integer
// cout << "id :" << stoi(obj["id"].asString()) <<endl;
// Parsing Line object with its internal objects
const Json::Value& lines = obj["lines"];
for (int i=0; i<lines.size();i++){
cout << "index : " << i << endl;
cout << "id:" << lines[i]["id"].asString() <<endl;
cout << "type:" << lines[i]["type"].asString() <<endl;
cout << "function:" << lines[i]["function"].asString() <<endl;
cout << "color:" << lines[i]["color"].asString() <<endl;
const Json::Value& poly = lines[i]["polyPoints"];
for (int j=0; j<poly.size();j++){
cout << "batch#"<<j<<endl;
cout << "latitude" << poly[j]["latitude"].asFloat()<<endl;
cout << "longitude" << poly[j]["longitude"].asFloat()<<endl;
cout << "altitude" << poly[j]["altitude"].asFloat()<<endl;
}
}
// Reading the OccupancyGrid object
// OccupancyGrid object is copied into constant to parse the arrays inside
const Json::Value& occupancyGrid = obj["occupancyGrid"];
cout << occupancyGrid.size() <<endl;
// The size of occupancyGrid is the used as number of iterations (#of rows)
for (int l=0; l<occupancyGrid.size();l++){
// Arrays inside occupancyGrid are copied into constant to parse the elements inside each array
const Json::Value& element = occupancyGrid[l];
// iterations over the size of the array in order to parse every element
cout << "row" << l << "--> ";
for (int k=0;k<element.size();k++){
cout << element[k].asFloat();
if(k<element.size()-1){ cout<< ",";}
}
cout << endl;
}
// Parsing roadSigns object as found in the file
// Need to understand the difference between format in the mail and the 1456 file
const Json::Value& roadsigns = obj["roadSigns"];
cout << "ArrayType: " << roadsigns["_ArrayType_"].asString()<<endl;
const Json::Value& ArraySize = roadsigns["_ArraySize_"];
for(int t=0;t<ArraySize.size();t++){
cout << ArraySize[t].asInt();
if (t<ArraySize.size()-1){ cout << " , ";}
}
cout<< endl;
if (roadsigns["_ArrayData_"].asString().empty()) {
cout << "ArrayData: "<<roadsigns["_ArrayData_"].asFloat(); }
else { cout << "ArrayData: empty "; }
cout <<endl;
test.close();
test.clear();
cout << "Done" << endl;
cout << "...." << endl;
cout << "...." << endl;
}
//else{
// std::cout << "No files ending in '" << extension << "' were found." << std::endl;
//}
}
Without access to the JSON library I can't help you too much, but the first obvious place for potential crashes would be if (fname.find(extension, (fname.length() - extension.length())) != string::npos). You need to make sure that your file name is longer than the size of your extension before making that call.
Also, for extremely deep directory trees you should put a limit on recursion, and all OSes I know of have some sort of character limit on directory and file names.