PDA

View Full Version : C++ overlapping output and adding extensions to output files



lordmorgul
05-09-2010, 07:14 PM
Hello. I've written this program which reads a preformatted text file with a list of countries and then sorts them, adds/modifies/deletes records and exports the modified list to another file.
I've got two problems with it. The first one is a more serious one, while the other one is a minor issue.
So, the bigger problem is with the output I get. When I display the sorted list, the fields overlap like this (in case you're wondering ─ the list of countries is in Polish): Imageshack - countries.png - Uploaded by lordmorgul (http://img294.imageshack.us/i/countries.png/)
I have absolutely no idea how to fix this thing.

The other issue is with the function for exporting the list to another text file. I would like to automatically add the .txt extension to the filename, but when I do
outfile+(".txt) I get this error:

menu.cpp: In function ‘void Menu(std::vector<COUNTRY, std::allocator<COUNTRY> >&)’:
menu.cpp:131: error: invalid operands of types ‘char [30]’ and ‘const char [5]’ to binary ‘operator+’

And when I change the outfile to a string, I get the following:

menu.cpp: In function ‘void Menu(std::vector<COUNTRY, std::allocator<COUNTRY> >&)’:
menu.cpp:131: error: no matching function for call to ‘std::basic_fstream<char, std::char_traits<char> >::open(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::_Ios_Openmode)’
/usr/include/c++/4.4/fstream:865: note: candidates are: void std::basic_fstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]

Here's the program:

panstwa.hpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>

using namespace std;

struct COUNTRY
{
string Name, Cont, Lang;
int Population, Area;
float Density;
};

fstream filein, fileout;
int Menu(vector<COUNTRY> &);
void Print(vector<COUNTRY> &);
char DisplayData();
char DisplayData_sub(char);
char Search();
void Search_sub(vector<COUNTRY> &, char);
void DeleteData(vector<COUNTRY> &);
void ModifyData(vector<COUNTRY> &);
void BubbleSortName(vector<COUNTRY> &, char);
void BubbleSortPopulation(vector<COUNTRY> &, char);
void BubbleSortArea(vector<COUNTRY> &, char);
void BubbleSortDensity(vector<COUNTRY> &, char);
void Help();

main.cpp

#include "panstwa.hpp"
#include "funkcje.cpp"
#include "menu.cpp"
#include "sort.cpp"

int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Incorrectly run program" << endl
<< "Run it this way:" << endl
<< "\tcountries.out <file>" << endl
<< "(where <file> is a text file" << endl;
exit(1);
}

else
{
filein.open(argv[1], ios::in);
if(!filein.good())
{
cout << "Couldn't open the file." << endl;
exit(1);
}

short lines=0;
char c;
while(!filein.eof())
{
filein.get(c);
if(c=='\n') lines++;
}

lines++;

if(filein.eof()) filein.clear();
filein.seekg(ios::beg);
vector<COUNTRY> Country(lines);

char znak;
for(int i=0; !filein.eof(); i++)
{
getline( filein, Country[i].Name, filein.widen(';'));
filein >> Country[i].Population >> znak;
filein >> Country[i].Area >> znak;
getline( filein, Country[i].Cont, filein.widen(';'));
getline( filein, Country[i].Lang, filein.widen('\n'));
float population = static_cast<float>(Country[i].Population);
float Area = static_cast<float>(Country[i].Area);
Country[i].Density = population/Area;
}

filein.close();
Menu(Country);

return 0;
}
}

menu.cpp

int Menu(vector<COUNTRY> &Country)
{
char choice;
float a, b;
cout << "Countries." << endl
<< "What would you like to do?" << endl << endl
<< "\t[d]isplay the list of countries." << endl
<< "\t[s]earch for a country." << endl
<< "\t[r]emove a record." << endl
<< "\t[a]dd a record." << endl
<< "\t[m]odify a record." << endl
<< "\t[e]xport the base to a text file." << endl
<< "\t[h]elp." << endl
<< "\t[q]uit." << endl << endl
<< "Choice: ";

do
{
cin >> choice;
if( (choice!='d') && (choice!='s') && (choice!='r') &&
(choice!='a') && (choice!='m') && (choice!='e') && (choice!='h') && (choice!='q'))
cout << endl << "Illegal option. Choose again:: ";
}

while( (choice!='d') && (choice!='s') && (choice!='r') &&
(choice!='a') && (choice!='m') && (choice!='e') && (choice!='h') && (choice!='q'));

char Option;
COUNTRY temp;
short in;
char outfile[30];
//string outfile;

switch(choice)
{
case 'd':
Option = DisplayData();
switch(Option)
{
case '1':
BubbleSortName(Country, DisplayData_sub(Option));
Print(Country);
break;
case '2':
BubbleSortPopulation(Country, DisplayData_sub(Option));
Print(Country);
break;
case '3':
BubbleSortArea(Country, DisplayData_sub(Option));
Print(Country);
break;
case '4':
BubbleSortDensity(Country, DisplayData_sub(Option));
Print(Country);
break;
default:
break;
}

cin.ignore();
getchar();
Menu(Country);
break;

case 's':
Option = Search();
Search_sub(Country, Option);
cin.ignore();
getchar();
Menu(Country);
break;

case 'r':
DeleteData(Country);
cin.ignore();
getchar();
Menu(Country);
break;

case 'a':
cout << "You want to add a country. Type in the following:" << endl
<< "Name (uppercase, eg. JAPAN): ";
cin.ignore();
getline(cin, temp.Name);
cout << "Population (integer): ";
cin >> temp.Population;
cout << "Area (integer): ";
cin.ignore();
cin >> temp.Area;

cout << "Continent (first uppercase, eg. Australia): ";
cin.ignore();
getline(cin, temp.Cont);
cout << "Language (all lowercase, eg. spanish): ";
getline(cin, temp.Lang);
a = static_cast<float>(temp.Population);
b = static_cast<float>(temp.Area);
temp.Density = a/b;
Country.push_back(temp);
in = Country.size() - 1;
cout << endl << "Here's the country's data: " << temp.Name << ": " << endl;
cout << "#" << in+1 << ": ";
cout << Country[in].Name << " | ";
cout << Country[in].Population << " | ";
cout << Country[in].Area << " | ";
cout << Country[in].Cont << " | ";
cout << Country[in].Lang << " | ";
cout << Country[in].Density;
cin.ignore();
getchar();
Menu(Country);
break;

case 'm':
ModifyData(Country);
cin.ignore();
getchar();
Menu(Country);
break;

case 'e':
cout << "Type in the name of the file to export: ";
cin >> outfile;
fileout.open(outfile, ios::out|ios::trunc);
if(fileout.good())
{
cout << endl << "Opened the file successfully.";
}

else
{
cout << endl << "Couldn't open the file" << endl;
return 1;
}

for(unsigned short i=0; i < Country.size(); i++)
{
fileout << Country[i].Name <<';'<<Country[i].Population <<';'<<Country[i].Area <<';'<<Country[i].Cont <<';'<< Country[i].Lang <<
';'<< Country[i].Density << endl;
}

fileout << '\0';
fileout.close();
cout << endl << "File export successful.";
cin.ignore();
getchar();
Menu(Country);
break;

case 'h':
Help();
cin.ignore();
getchar();
Menu(Country);
cout << "Press [return] to get back to the menu" << endl;
break;

case 'q':
cout << "Finished." << endl;
exit(0);

default:
break;
}
}


funkcje.cpp

void Print(vector<COUNTRY> &Country)
{
int length = Country.size();
for(int i=0; i < length; i++)
{
cout << "#" << i+1 << ": ";
cout << Country[i].Name << " | ";
cout << Country[i].Population << " | ";
cout << Country[i].Area << " | ";
cout << Country[i].Cont << " | ";
cout << Country[i].Lang << " | ";
cout << Country[i].Density;
cout << endl;
//if ((i+1)%15==0) //getchar();
}
}

char DisplayData()
{
char choice;
cout << "How do you want to sort the countries?" <<endl;
cout << "\t1) By name." <<endl;
cout << "\t2) By population." <<endl;
cout << "\t3) By area." <<endl;
cout << "\t4) By population density." <<endl;
cout << "Option: ";

do
{
cin >> choice;
if((choice!='1') && (choice!='2') && (choice!='3') && (choice!='4'))
cout << endl << "Illegal option. Choose again:";
}

while((choice!='1') && (choice!='2') && (choice!='3') && (choice!='4'));
return choice;
}

char DisplayData_sub(char Option)
{
char choice;
switch(Option)
{
case '1':
cout << "How do you want to sort the names?" << endl;
cout << "\tm) descending order." << endl;
cout << "\tr) ascending order." << endl;
cout << "Choice: ";

do
{
cin >> choice;
if((choice!='m') && (choice!='r'))
cout << endl << "Illegal option. Choose again:";
}

while((choice!='m') && (choice!='r'));
break;

case '2':
cout << "You want to sort the list by population:" << endl;
cout << "\tm) in descending order." << endl;
cout << "\tr) in ascending order." << endl;
cout << "Choice: ";
do
{
cin >> choice;
if((choice!='m') && (choice!='r'))
cout << endl << "Illegal option. Choose again:";
}

while((choice!='m') && (choice!='r'));
break;

case '3':
cout << "You want to sort the list by area:" << endl;
cout << "\tm) in descending order." << endl;
cout << "\tr) in ascending order." << endl;
cout << "Wybor: ";

do
{
cin >> choice;
if((choice!='m') && (choice!='r'))
cout << endl << "Illegal option. Choose again:";
}

while((choice!='r') && (choice!='m'));
break;

case '4':
cout << "You want to sort the list by population density:" << endl;
cout << "\tm) in descending order." << endl;
cout << "\tr) in ascending order." << endl;
cout << "Wybor: ";

do
{
cin >> choice;
if((choice!='m') && (choice!='r'))
cout << endl << "Illegal option. Choose again:";
}

while((choice!='m') && (choice!='r'));
break;
default:
break;
}

return choice;
}

char Search()
{
char choice;
cout << "How do you want to search the country:" << endl
<< "\t1) By name." << endl
<< "\t2) By continent." << endl
<< "\t3) By language." << endl << "Wybor: ";

do
{
cin >> choice;
if((choice!='1') && (choice!='2') && (choice!='3'))
cout << endl << "Illegal option. Choose again:: ";
}

while((choice!='1') && (choice!='2') && (choice!='3'));
return choice;
}

void Search_sub(vector<COUNTRY> &Country, char Option)
{
unsigned short i=0;
bool flag = false;
string temp;
unsigned int result;

switch(Option)
{
case '1':
cout << "Type in the country's name (in capitals, eg. CANADA): ";
cin.ignore();
getline(cin, temp);
while(i != Country.size())
{
result = Country[i].Name.find(temp);
if(result!=string::npos)
{
cout << "#" << i << ": " << Country[i].Name << " | " << Country[i].Population << " | " << Country[i].Area << " | " << Country[i].Cont << " | " << Country[i].Lang << " | " << Country[i].Density << endl;
flag = true;
}

i++;
}

if( flag == false ) cout << endl << "The country couldn't be found.";
break;

case '2':
cout << "Type in the country's continent (first capital letter, eg. Africa): ";
cin.ignore();
getline(cin, temp);
//result = strstr( Country[i].Cont, temp );

while(i != Country.size())
{
result = Country[i].Cont.find(temp);
if(result!=string::npos)
{
cout << "#" << i << ": " << Country[i].Name << " | " << Country[i].Population << " | " << Country[i].Area << " | " << Country[i].Cont << " | " << Country[i].Lang << " | " << Country[i].Density;
flag = true;
cout << endl;
}

i++;
}
if( flag == false ) cout << endl << "Unknown n ame.";
break;
case '3':
cout << "Type in the language (lowercase, eg. norwegian): ";
cin.ignore();
getline(cin, temp);

while(i != Country.size())
{
result = Country[i].Lang.find(temp);

if(result!=string::npos)
{
cout << "#" << i << ": " << Country[i].Name << " | " << Country[i].Population << " | " << Country[i].Area << " | " << Country[i].Cont << " | " << Country[i].Lang << " | " << Country[i].Density;
flag = true;
cout << endl;
}

i++;
}

if( flag == false ) cout << endl << "Unknown name.";
break;
default:
break;
}
}

void ModifyData(vector<COUNTRY> &Country)
{
string temp;
unsigned short i=0, tmp;
bool flag = false;
char choice;
cout << "Type in the name of the country you wish to modify (uppercase, eg. ZIMBABWE):" << endl << "Nazwa: ";
cin.ignore();
getline(cin, temp);

while(i != Country.size())
{
if(temp == Country[i].Name)
{
cout << endl << "Here's the country's current data: " << temp << ": " << endl << "#" << i << ": " << Country[i].Name << " | " << Country[i].Population << " | " << Country[i].Area << " | " << Country[i].Cont << " | " << Country[i].Lang << " | " << Country[i].Density << endl;
tmp = i;
flag = true;
}

i++;
}

if( flag == false ) cout << endl << "Couldn't find the country.";
else if(flag == true)
{
cout << endl << "Rename the country?" << endl << "\t1) Yes." << endl << "\t2) No." << endl << "Wybor: ";

do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again:";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
cout << endl << "New name: ";
cin.ignore();
getline(cin, Country[tmp].Name);
}

cout << endl << "Change the population?"
<< endl << "\t1) Yes."
<< endl << "\t2) No."
<< endl << "Choice: ";

do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again:";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
cout << "New population (integer, eg. 23000000): ";
cin >> Country[tmp].Population;
}

cout << endl << "Change the area?" << endl
<< "\t1) Yes." << endl
<< "\t2) No." << endl
<< "Option: ";

do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again:";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
cout << "New area: ";
cin >> Country[tmp].Area;
}

cout << endl << "Change the continent? " << endl
<< "\t1) Yes." << endl
<< "\t2) No." << endl
<< "Option: ";

do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again:";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
cout << "New continent (first uppercase, rest lowercase, eg. Asia): ";
cin.ignore();
getline(cin, Country[tmp].Cont);
}

cout << endl << "Change the language?" << endl
<< "\t1) Yes." << endl
<< "\t2) No." << endl
<< "Option: ";

do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again:: ";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
cout << "New language (lowercase, eg. german): ";
cin.ignore();
getline(cin, Country[tmp].Lang);
}

cout << endl << "Here's the updated data: " << temp << ": " << endl << "#" << tmp << ": " << Country[tmp].Name << " | " << Country[tmp].Population << " | " << Country[tmp].Area << " | " << Country[tmp].Cont << " | " << Country[tmp].Lang << " | ";

float a = static_cast<float>(Country[tmp].Population);
float b = static_cast<float>(Country[tmp].Area);
float c = a/b;
Country[tmp].Density = c;

cout << Country[tmp].Density;
}
}

void DeleteData(vector<COUNTRY> &Country)
{
string temp;
unsigned short i=0, tmp;
bool flag = false;
char choice;
cout << "Type in the name of the country you wish to delete: ";
cin.ignore();
getline(cin, temp);

while(i != Country.size())
{
if(temp == Country[i].Name)
{
tmp = i;
flag = true;
}

i++;
}

if( flag == false ) cout << endl << "Unknown name.";
else
{
cout << endl << "Here's the current data of the country: " << temp << ": " << endl << "#" << tmp << ": " << Country[tmp].Name << " | " << Country[tmp].Population << " | " << Country[tmp].Area << " | " << Country[tmp].Cont << " | " << Country[tmp].Lang << " | " << Country[tmp].Density << endl
<< "Are you sure you want to delete it?: " << endl
<< "1. Tak." << endl << "2. Nie." << endl << "Option: ";
do
{
cin >> choice;
if( (choice!='1') && (choice!='2'))
cout << endl << "Illegal option. Choose again::";
}

while( (choice!='1') && (choice!='2'));
if(choice == '1')
{
Country.erase(Country.begin() + tmp);
cout << endl << "Country deleted.";
}

else if (choice == '2') cout << endl << "OK. Country left untouched.";
}
}

void Help()
{
cout << endl << "TODO: create help." << endl;
}


sort.cpp

void BubbleSortName(vector<COUNTRY> &Country, char choice)
{
int i, j, flag = 1;
COUNTRY temp;
int length = Country.size( );
for(i = 1; (i <= length) && flag; i++)
{
flag = 0;
for (j=0; j < (length -1); j++)
{
switch(choice)
{
case 'm':
if (Country[j+1].Name > Country[j].Name)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}

break;

case 'r':
if (Country[j+1].Name < Country[j].Name)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}

break;
}
}
}
}

void BubbleSortPopulation(vector<COUNTRY> &Country, char choice)
{
int i, j, flag = 1;
COUNTRY temp;
int length = Country.size( );
for(i = 1; (i <= length) && flag; i++)
{
flag = 0;
for (j=0; j < (length -1); j++)
{

switch(choice)
{
case 'm':
if (Country[j+1].Population > Country[j].Population)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}
break;

case 'r':
if (Country[j+1].Population < Country[j].Population)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}
break;
}
}
}
}

void BubbleSortArea(vector<COUNTRY> &Country, char choice)
{
int i, j, flag = 1;
COUNTRY temp;
int length = Country.size( );
for(i = 1; (i <= length) && flag; i++)
{
flag = 0;
for (j=0; j < (length -1); j++)
{
switch(choice)
{
case 'm':
if (Country[j+1].Area > Country[j].Area)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}
break;

case 'r':
if (Country[j+1].Area < Country[j].Area)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}

break;
}
}
}
}

void BubbleSortDensity(vector<COUNTRY> &Country, char choice)
{
int i, j, flag = 1;
COUNTRY temp;
int length = Country.size( );
for(i = 1; (i <= length) && flag; i++)
{
flag = 0;
for (j=0; j < (length -1); j++)
{
switch(choice)
{
case 'm':
if (Country[j+1].Density > Country[j].Density)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}
break;

case 'r':
if (Country[j+1].Density < Country[j].Density)
{
temp = Country[j];
Country[j] = Country[j+1];
Country[j+1] = temp;
flag = 1;
}
break;
}
}
}
}


edit: I also attached the file I'm working on with this program.

jimblumberg
05-10-2010, 08:38 AM
For your problem of overlapping code look for the linefeed character '\r' in your input strings.
If the file is from a Windows machine the end of line is '\r\n' and on Linux it is just '\n'

For your question of adding the '.txt' to the file name if you use a string instead of a
character array then it will work if you use outfile.c_str() in the fileout.open call



std::string outfile;
cout << "Type in the name of the file to export: ";
cin >> outfile;
fileout.open(outfile.c_str(), ios::out|ios::trunc);

lordmorgul
05-10-2010, 12:44 PM
I don't get how c_str() works... Where do I add the ".txt"?
And as for the linefeed character ─ I don't know how to modify the code ─ when I change the char c to a string I get tons of errors.

jimblumberg
05-10-2010, 01:35 PM
add the ".txt" after cin.



std::string outfile;
cout << "Type in the name of the file to export: ";
cin >> outfile;
outfile += ".txt";
fileout.open(outfile.c_str(), ios::out|ios::trunc);

lordmorgul
05-10-2010, 04:09 PM
Oh, wow, that was actually quite obvious, I kept trying to enter it after c_str() ;-) Thank you very much.
But I still have no luck with fixing the overlapping output. I forgot to mention, that after exporting the data to another file ─ it looks the way it should, it's only the display in the program that's wrong.

jimblumberg
05-10-2010, 06:31 PM
In main after the line:


getline( filein, Country[i].Lang, filein.widen('\n'));


add the following code


std::string::size_type idx;
// Remove the cursor return char if found.
if((idx=Country[i].Lang.find.wi("\r")) != std::string::npos)
Country[i].Lang.erase(idx,1);

This should detect the linefeed character if present and remove it.

Jim

lordmorgul
05-11-2010, 03:38 AM
I get this error after inserting your code:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:57: error: ‘Country.std::vector<_Tp, _Alloc>::operator[] [with _Tp = COUNTRY, _Alloc = std::allocator<COUNTRY>](((unsigned int)i))->COUNTRY::Lang.std::basic_string<_CharT, _Traits, _Alloc>::find [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ does not have class type

jimblumberg
05-11-2010, 07:38 AM
if((idx=Country[i].Lang.find.wi("\r")) != std::string::npos)
Country[i].Lang.erase(idx,1);


Sorry had a typo, remvoe the wi and it should work



if((idx=Country[i].Lang.find("\r")) != std::string::npos)
Country[i].Lang.erase(idx,1);

lordmorgul
05-11-2010, 07:57 AM
That worked. Thank you very much!

lordmorgul
05-11-2010, 08:26 AM
Oh, I noticed one more thing... When I sort the list by names it displays AFGANISTAN (which is the first record) on the opposite end of the list (eg. when I sort it descending, it gets displayed first).