and so on. I have searched the forum and found nothing that I can tell relates to reading files like this. I have used the fstream header before for reading numbers and doing stuff with them but an address will have spaces, and fstream stops on a space.
I also need to be able to append the file when a new record needs added.
#include <stdio.h>
#include <malloc.h>
#include <windows.h>
//Frees a buffer
void VirtualFreeHuge(char** pString, int uBound)
{
//free each of the items
for(int i = 0; i <= uBound; i++)
free(pString[i]);
//free the item itself
free(pString);
};
TCHAR** VirtualSplitString(TCHAR* pString, TCHAR sep, int& uBound)
{
unsigned long s = 0; unsigned long i = 0;
TCHAR** pArray = (TCHAR**)calloc(strlen(pString), sizeof(TCHAR*));
//allocate empty storage
//the first array
pArray[0] = (TCHAR*)calloc(1024, sizeof(TCHAR));
//separate an array...
while(*pString)
{
//go through the string, find position
if(*pString == sep)
{
i++;
s = 0; //current position
//allocate space for new input
pArray[i] = (TCHAR*)calloc(1024, sizeof(TCHAR));
}
else
{
//get the current character and set it
pArray[i][s] = *pString;
//increase character position
s++;
}
//increase string position
pString++;
}
uBound = ++i;
//return the pArray data type
return pArray;
};
int main(int argc, char* argv[])
{
CHAR sz[1024];
FILE* f = fopen("C:\\file.txt", "r");
while(fgets(sz, 1024, f))
{
int u;
char** s = VirtualSplitString(sz, ',', u);
for(int i = 0; i < u; i++)
printf("%s\n", s[i]);
VirtualFreeHuge(s, u);
}
fclose(f);
return 0;
}
fclose(f);
The program is a pizza order program so the file would be like so.
"5551212","Doe","John","1212 Mockingbird Ln"
I need to be able to extract the info from within the quotes.
I have started by reading one char at a time and kina of parse it til I get to a '\n' char.
Is that the best way to do it. made_of_asp was using the malloc.h header which if I remember what that is, its for grabbing chucks of memory from the heap and such, but his code lost me.
I guess the answer is it could generic so it could read any comma-delimited file.
Well, specialized is easier to write and to use...
And especially to understand. You wouldn't want me to come up with nested vectors or vectors of maps.
Here's specialized code for you.
Code:
#include <algorithm> // container manipulation
#include <string> // easy strings
#include <vector> // growable array
using namespace std;
// struct representing one line of data in the file
struct file_entry
{
string sPhone;
string sLast;
string sFirst;
string sAddress;
};
// prototypes
void read_your_file(const string &strFilename, vector<file_entry> &out);
void split_string(const string &s, vector<string> & out, char split_at);
ostream & operator <<(ostream &os, const file_entry &fe);
istream & operator >>(istream &is, file_entry &fe);
int main(int argc, char *argv[])
{
// storage location for the data
vector<file_entry> vc;
// read in data
// call app like
// app data.txt
// where data.txt is the file you want to read
read_your_file(argv[1], vc);
// output the array
for(vector<file_entry>::iterator it = vc.begin(); it != vc.end(); ++it)
cout << *it << '\n';
// ensure data is displayed
cout.flush();
return 0;
}
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t.clear();
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
copy(stay, run, back_inserter(t));
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t.clear();
t.reserve(run-stay);
copy(stay, run, back_inserter(t));
out.push_back(t);
}
// reads in one file_entry from any stream
istream & operator >>(istream &is, file_entry &fe)
{
// temporary
string t;
// read one line from the stream
getline(is, t);
// receives substrings
vector<string> vs;
// split the line
split_string(t, vs, ',');
// fill the struct
// substr removes the "
fe.sPhone = vs[0].substr(1, vs[0].size()-2);
fe.sLast = vs[1].substr(1, vs[1].size()-2);
fe.sFirst = vs[2].substr(1, vs[2].size()-2);
fe.sAddress = vs[3].substr(1, vs[3].size()-2);
return is;
}
// output a file_entry to a stream
ostream & operator <<(ostream &os, const file_entry &fe)
{
return os << fe.sPhone.c_str() << ' ' << fe.sLast.c_str() << ' '
<< fe.sFirst.c_str() << ' ' << fe.sAddress.c_str();
}
// read in a file of your format
void read_your_file(const string &strFilename, vector<file_entry> &out)
{
// the stream
ifstream ifs;
// open the file
ifs.open(strFilename.c_str());
// temporary
file_entry t;
// while the end is not reached
while(!ifs.eof()) {
// read in one entry
ifs >> t;
// and add it to the array
out.push_back(t);
}
}
All the buzzt CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
I am going to take this and fire it into my program and see how it works. It will probably be tomorrow before I can get back to you on it.
When and if I have questions, would you be willing to answer them for me when the time comes. I am wanting to understand what it does and I see your comments. Just want to be sure I understand what I am going to turn in.
I still have not been able to get this to compile and run. I changed the t.clear to t = "" then I got an error 4786
I figured out what the error was and added:
#pragma warning(disable:4786) to my code
Now I have this
c:\program files\microsoft visual studio\vc98\include\iterator(82) : error C2039: 'push_back' : is not a member of 'basic_string<char,struct std::char_traits<char>,class std::allocator<char> >'
c:\program files\microsoft visual studio\vc98\include\iterator(82) : while compiling class-template member function 'class std::back_insert_iterator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &_
_thiscall std::back_insert_iterator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >:perator =(const char &)'
Error executing cl.exe.
Do you have any ideas here.
I think I understand what the code is doing and if I code run it and step through it, I would be ok.
Jerel
ps
just to be safe here is the code I am running. It is the same code you posted with the exceptions of the t.clear, two more header files, and the pragma statement
Code:
#pragma warning(disable:4786)
#include <algorithm> // container manipulation
#include <string> // easy strings
#include <vector> // growable array
#include <fstream>
#include <iostream>
using namespace std;
// struct representing one line of data in the file
struct file_entry
{
string sPhone;
string sLast;
string sFirst;
string sAddress;
};
// prototypes
void read_your_file(const string &strFilename, vector<file_entry> &out);
void split_string(const string &s, vector<string> & out, char split_at);
ostream & operator <<(ostream &os, const file_entry &fe);
istream & operator >>(istream &is, file_entry &fe);
int main(int argc, char *argv[])
{
// storage location for the data
vector<file_entry> vc;
// read in data
// call app like
// app data.txt
// where data.txt is the file you want to read
read_your_file(argv[1], vc);
// output the array
for(vector<file_entry>::iterator it = vc.begin(); it != vc.end(); ++it)
cout << *it << '\n';
// ensure data is displayed
cout.flush();
return 0;
}
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t = "";
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
copy(stay, run, back_inserter(t));
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t = "";
t.reserve(run-stay);
copy(stay, run, back_inserter(t));
out.push_back(t);
}
// reads in one file_entry from any stream
istream & operator >>(istream &is, file_entry &fe)
{
// temporary
string t;
// read one line from the stream
getline(is, t);
// receives substrings
vector<string> vs;
// split the line
split_string(t, vs, ',');
// fill the struct
// substr removes the "
fe.sPhone = vs[0].substr(1, vs[0].size()-2);
fe.sLast = vs[1].substr(1, vs[1].size()-2);
fe.sFirst = vs[2].substr(1, vs[2].size()-2);
fe.sAddress = vs[3].substr(1, vs[3].size()-2);
return is;
}
// output a file_entry to a stream
ostream & operator <<(ostream &os, const file_entry &fe)
{
return os << fe.sPhone.c_str() << ' ' << fe.sLast.c_str() << ' '
<< fe.sFirst.c_str() << ' ' << fe.sAddress.c_str();
}
// read in a file of your format
void read_your_file(const string &strFilename, vector<file_entry> &out)
{
// the stream
ifstream ifs;
// open the file
ifs.open(strFilename.c_str());
// temporary
file_entry t;
// while the end is not reached
while(!ifs.eof()) {
// read in one entry
ifs >> t;
// and add it to the array
out.push_back(t);
}
}
// this takes a string and splits it into an array of smaller strings
// it's splitted every time split_at is encountered
void split_string(const string &s, vector<string> & out, char split_at)
{
// for searching the string
string::const_iterator stay, run;
// set stay to the start of the string
stay = s.begin();
// temporary
string t;
// loop run through the string, from front to back
for(run=stay; run != s.end(); ++run)
{
// if encountered split char...
if(*run == split_at)
{
// ...clear the temporary value...
t.erase();
// (speeds it up a little)
t.reserve(run-stay);
// ..., copy current substring to temporary...
t.append(stay, run);
// ...and add it to the array.
out.push_back(t);
// Finally, let the next substring begin directly after the splitting char.
stay = run+1;
}
}
// same as above for the last piece (from last split char to end of string)
t.erase();
t.reserve(run-stay);
t.append(stay, run);
out.push_back(t);
}
Stupid VC++6 *mumble*...
All the buzzt CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
I am having a bit of trouble with this code for some reason. I basically have your code but I have changed it just a bit to make it my own and to help me understand it better.
anyway, the problem is, when I call the Parse function, the program crashes and if I debug it, I get a fatal exception. I dont have anything different than you. Its crashing when I pass the values to the function. I have look on here and read the books I have and I dont anything wrong.
void ParseString(const string &strParse, vector<string> &v)
{
// This sub will parse the string and add it to the vector
// We are passing by reference the string to parse and
// the vector to store it in
string::const_iterator start,stop; //This will help count through the string
string sTemp; //Temp string for storing the parsed variable
stop = strParse.begin(); //Set this to the fron of the string
//This loop will parse strParse. It will look for the comma and grab
//everything between start and stop until wee reach the end of the line
for (start = stop; start != strParse.end(); start++ )
{
//See if we are ready to parse
//typcast the ',' so we cansave some memory
if ( *start == char(',') ) //If where we are looking is a comma, then time to parse
{
sTemp.erase(); //Make sure we are empty
sTemp.reserve(start-stop); //Reserve the right memory.
sTemp.append( stop, start ); //Copy out what we need
v.push_back( sTemp ); //Add the new sting to the vector
stop = start + 1; //Move the pointer past the comma
}
//When we exit the loop, we will need to grab he last of the line
sTemp.erase(); //Make sure we are empty
sTemp.reserve(start-stop); //Reserve the right memory.
sTemp.append( stop, start ); //Copy out what we need
v.push_back( sTemp ); //Add the new sting to the vector
}
}
and here is how I call it, and how the variable are declared
There it is. I only added the .cpp and the text file I am using.
I changed the file so it had no "" in the fields. Mainly just to give me a chance to play with the code and make it different so I could understand it better. Its far from finished but it is getting there.
I deleted the byref variable and then readded them one at a time to see what was causing the problem and it started working. I eyeballed the code to death, maybe there was something not quite right.