Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

reading delimiter separatedstring-valuesfrom file into variables???

22 views
Skip to first unread message

marane moll

unread,
Jun 3, 2003, 1:58:17 PM6/3/03
to
Hello

I'm programming with fstream and I want to read some comma-separated string
values from file into the fitting variables (name, prename, age ...). Is
there any fast way to do it?

Thank you
Sincerely
Marane


MiniDisc_2k2

unread,
Jun 3, 2003, 5:45:40 PM6/3/03
to
Well there is an easy way to do it (in that you can tell it that the
variables are separated by commas), but you cannot give it string variables.
If you are just learning C/C++, this may blow your mind a bit, but I'll
explain later:

(Note that there's a lot of explaining here, but I would recommend reading
it. Once you do, you'll have learned a lot about one of the hardest things
in C/C++)

#include <string.h> // 1
#include <fstream.h> // 2
int main() // 3
{ // 4
string str; // 5
char* buffer; // 6
fstream file("file.txt", ios::in); // 7

buffer = new char[50]; // 8
file.get(buffer, 50, ','); // 9
name = buffer; // 10
delete buffer; // 11

return (0); // 12
}

Here's the explanation (note the line numbers are in the comments):

Lines 1-4: Standard operating proceedures. Include libraries, start main.
I'm sure you understood that part
Line 5: Declaration of a string named str. Pretty simple
Line 6: Here we declare a pointer to a character. If you don't understand
this, I'll explain soon. You're about to learn one of the most important and
confusing topics of C/C++
Line 7: Here we open the file "file.txt." for reading.

IF YOU ALREADY UNDERSTAND POINTERS, YOU CAN SKIP THIS SECTION
Ok, now we really get into pointers. In the olden days, programmers were
left in the dark with how to deal with strings. C did not give us the
capability to use the "string" type, we had to make a bunch of chars
(character variables), and link them together into a string. Therefore, we
used a pointer. A pointer is the address to something. Here, we have the
address of a character. Why do we use this? Simple. By using the address of
the first character in the string, we can refer to the entire string with
one variable. Really, you don't have to worry about this. All you have to
know is this:
- Line 8 makes the string 50 characters long. The operator "new"
allocates space in the ram for those 50 characters. If you need it longer
than this, you will need to increase the size. If it's not big enough, you
will "exceed array bounds" and make your program crash due to an "access
violation" or "general protection fault" (GPF). Your program actually
crashes due to windows. It automatically shuts down your program to prevent
it from corrupting your ram (and causing your entire system to crash). Just
ensure that the number inside the brackets is large enough for the entire
string PLUS ONE. (One extra because of something called the "null
terminator," which indicates the end of a string).
END POINTERS SECTION

Line 9: Here you use the address you have in the pointer which was set by
the "new" operator to store the string. It will store up to 49 characters
(that's 50-1), or until it reaches the comma. That's what the third
parameter indicates, the delimiter is the comma (instead of the default, the
newline character, or '\n'). So it will read 49 characters or until it
reaches a comma, and store it in buffer. Note that if you made the number in
line 8 larger, you should also set this number to the same also.

Line 10: Here we convert the "character pointer" to a string variable. This
is automatically taken care of for us, so no problems here.
Line 11: Here we delete the character pointer. This is EXTREMELY IMPORTANT
WITH POINTERS. If you do not delete the variable you created with new, then
you will have created a "memory leak." This is space which your program has
exclusive access to, but which is not used anymore. Basically, it's wasted
ram, and it isn't freed until you restart your computer. Actually, many
compilers add some code at the end to fix any memory leaks when your program
quits (delete any undeleted variables), but it's still good practice to
delete them yourself.

Line 12: Simple end-of-program return call.

Well that's about it. Basically, we used the "get" function from the fstream
class to get a string up to 49 characters long or until it reaches a comma,
and store it into name. Congratulations, you have just learned how to use
pointers!

Hope that helped!
Good luck with your programming!
-- MiniDisc_2k2

"marane moll" <mar...@gmx.li> wrote in message
news:bbinc1$a5v$03$1...@news.t-online.com...

John Harrison

unread,
Jun 3, 2003, 5:58:23 PM6/3/03
to

"MiniDisc_2k2" <Matt...@cox.net> wrote in message
news:8G8Da.2268$oL4....@news2.east.cox.net...

> Well there is an easy way to do it (in that you can tell it that the
> variables are separated by commas), but you cannot give it string
variables.
> If you are just learning C/C++, this may blow your mind a bit, but I'll
> explain later:
>
> (Note that there's a lot of explaining here, but I would recommend reading
> it. Once you do, you'll have learned a lot about one of the hardest things
> in C/C++)
>
> #include <string.h> // 1
> #include <fstream.h> // 2
> int main() // 3
> { // 4
> string str; // 5
> char* buffer; // 6
> fstream file("file.txt", ios::in); // 7
>
> buffer = new char[50]; // 8
> file.get(buffer, 50, ','); // 9
> name = buffer; // 10
> delete buffer; // 11
>
> return (0); // 12
> }
>

1) The header for the C string functions (not C++)
2) A non-standard header
5) Compile error - unknown type string
10) Undeclared variable name

Also the needless and limitting use of a char buffer, why not just read
directly into name?

Here's how to really do it (but untested code, so feel free to point out the
faults)

#include <string>
#include <fstream>
#include <sstream>
using namespace std;

int main()
{
ifstream file("file.txt");
string line;
// read one line at a time
while (getline(file, line))
{
// put the line into a buffer so we can read from it again
istringstream buffer(line);
// read each word, comma seperated
string word;
while (getline(buffer, word, ','))
{
// do something with word
}
}
}

john


Bowen

unread,
Jun 3, 2003, 6:24:10 PM6/3/03
to
John Harrison wrote:
> "MiniDisc_2k2" <Matt...@cox.net> wrote in message
> news:8G8Da.2268$oL4....@news2.east.cox.net...
>
>>Well there is an easy way to do it (in that you can tell it that the
>>variables are separated by commas), but you cannot give it string
>
> variables.
>
>>If you are just learning C/C++, this may blow your mind a bit, but I'll
>>explain later:
>>
>>(Note that there's a lot of explaining here, but I would recommend reading
>>it. Once you do, you'll have learned a lot about one of the hardest things
>>in C/C++)
>>
>>#include <string.h> // 1
>>#include <fstream.h> // 2
>>int main() // 3
>>{ // 4
>> string str; // 5
>> char* buffer; // 6
>> fstream file("file.txt", ios::in); // 7
>>
>> buffer = new char[50]; // 8
>> file.get(buffer, 50, ','); // 9
>> name = buffer; // 10
>> delete buffer; // 11
>>
>> return (0); // 12
>>}
>>
>
>
> 1) The header for the C string functions (not C++)

Well it should compile regardless. To lessen the chances of namespace
problems, since you're using the damn C libraries anyways, just mix C
with C++.

Spare the flames. Yes it's off topic, but there's no need to go nasty
at him for doing what he does out of style. It is my understanding that
all C++ compilers compile C by the standard. It is also my
understanding that all, if not... then most, will compile mixed code.

If that's not the case, with more than one widely used c++ compiler that
conforms to the standard, sorry I said not to go crazy at him.

--
--Bowen--

Aaron Kincaid

unread,
Jun 3, 2003, 6:41:43 PM6/3/03
to
"marane moll" <mar...@gmx.li> wrote in message news:<bbinc1$a5v$03$1...@news.t-online.com>...

How about...read in a line and use strtok to get the tokens. That is
perhaps the simplest way. Remember strtok is not thread safe though.
Here is some example code.

// Open file
ifstream fin("C:\\file.txt");

// Check that open succeeded
if (!fin) {
// Read in a line
char buffer[256];
fin.getline(buffer, 255);

// Read in first token
char* token = strtok(buffer, ",");

// Read in the rest of the tokens
while (token) {
token = strtok(NULL, ",");
}

// Close the file
fin.close();
}

Thomas Matthews

unread,
Jun 3, 2003, 7:13:49 PM6/3/03
to

As a friendly attack on your code: you don't need to copy the
line twice. One can extract or parse the string using the
"find" methods or substring methods without having to make
a duplicate (thus wasting time and memory).

Also, one has to worry about having commas (',') embedded
within the string. This is one of the reasons that the
C and C++ languages have the "escape" character: so that
delimiters can be embedded into the string.

The Original Poster (OP) should study the "find" and "substr"
methods of the std::string class. Also use a search engine
and search this newsgroup for "comma separated OR csv".

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
http://www.sgi.com/tech/stl -- Standard Template Library

Thomas Matthews

unread,
Jun 3, 2003, 7:16:01 PM6/3/03
to

Nice, but your solution needs a fixed area of memory for an
unknown size of a text string. The OP should use the std::string
facility which takes care of memory allocation. The std::string
class also comes with "find" and "substr" methods.

Also note that the strtok() function _modifies_ the character
array.

John Harrison

unread,
Jun 4, 2003, 12:54:16 AM6/4/03
to

"Bowen" <ten.s...@newoB.com> wrote in message
news:bbj76f$a5jb2$1...@ID-159243.news.dfncis.de...

The point was that it was being used as a substitute for <string>. The
poster used std::string later in the code.

>
> Spare the flames. Yes it's off topic, but there's no need to go nasty
> at him for doing what he does out of style. It is my understanding that
> all C++ compilers compile C by the standard. It is also my
> understanding that all, if not... then most, will compile mixed code.
>
> If that's not the case, with more than one widely used c++ compiler that
> conforms to the standard, sorry I said not to go crazy at him.
>

My post was a bit mean, especially as MiniDisc was obviously keen to help,
and I don't want to discourage contributions. But the post contained many
factual errors and the code posted would not have compiled. Maybe he'll
compile before posting next time.

john


Bowen

unread,
Jun 4, 2003, 1:11:22 AM6/4/03
to

I understand the rest, but the regulars constantly complaining about the
headers gets tiring. It's off-topic, yes, but when has anything
followed the rules? Sorry to go off at you, the regulars here get
annoying when they say stupid things like "that's a c-header."

I could've sworn I read on Bjorne's site that C++ compilers support C by
a standard, anyways, so saying they're C headers is really a moot point
to the fact that it'll compile. But the main reason I think people do
what he did is to avoid namespace issues. So, by the standard (or from
what I remember from it), they're C headers, but they compile with
C-code mixed with a C++ application.

Anyways, sorry for attacking you. I did notice his other problems, but
that one stuck out at me. I said to myself, "Someone's going to comment
on the C-headers soon."

--
--Bowen--

John Harrison

unread,
Jun 4, 2003, 1:20:22 AM6/4/03
to

"Bowen" <ten.s...@newoB.com> wrote in message
news:bbjv1v$a75dd$1...@ID-159243.news.dfncis.de...

I'll say it again, I wasn't complaining about the C header. C is part of C++
and therefore C headers are perfectly on topic. I was complaining because
the poster apparenty believed that <string.h> declares the string class,
which is incorrect. I could have made that clearer in my original post.

>
> I could've sworn I read on Bjorne's site that C++ compilers support C by
> a standard, anyways, so saying they're C headers is really a moot point
> to the fact that it'll compile. But the main reason I think people do
> what he did is to avoid namespace issues.

I could accept that for <fstream.h> but not for <string.h>.

> So, by the standard (or from
> what I remember from it), they're C headers, but they compile with
> C-code mixed with a C++ application.
>
> Anyways, sorry for attacking you. I did notice his other problems, but
> that one stuck out at me. I said to myself, "Someone's going to comment
> on the C-headers soon."
>

No problem, I didn't think you were attacking me.

john


Bowen

unread,
Jun 4, 2003, 1:32:00 AM6/4/03
to

Yeah I know. Others seem to disagree with me that C++ was a superset of
C. Or C is a subset of C++... whichever terms float your boat. But you
agree with me, that's good. :)

According to Stroustrup, it is, but not in the strict sense of it being
completely 100% compatible. Although he claims it could be if some of
the conflicts were dealt with... he goes on to say there is no logical
reason for the conflicts. His website is neat to read though. Maybe I
read it wrong, who knows.

>>I could've sworn I read on Bjorne's site that C++ compilers support C by
>>a standard, anyways, so saying they're C headers is really a moot point
>>to the fact that it'll compile. But the main reason I think people do
>>what he did is to avoid namespace issues.
>
>
> I could accept that for <fstream.h> but not for <string.h>.

I'm confused though (I've never used the string class), is cstring the
actual string class header or is cstring the correct C++ header for the
c header string.h?

>>So, by the standard (or from
>>what I remember from it), they're C headers, but they compile with
>>C-code mixed with a C++ application.
>>
>>Anyways, sorry for attacking you. I did notice his other problems, but
>>that one stuck out at me. I said to myself, "Someone's going to comment
>>on the C-headers soon."
>>
>
>
> No problem, I didn't think you were attacking me.

Just don't turn into Neil. ;)

--
--Bowen--

John Harrison

unread,
Jun 4, 2003, 2:13:51 AM6/4/03
to
>
> I'm confused though (I've never used the string class), is cstring the
> actual string class header or is cstring the correct C++ header for the
> c header string.h?

Either <cstring> or <string.h> is correct for the C string functions in a
C++ program.

Incidentally one difference between C and C++ with regards to <string.h> is
that in C++ <sting.h> (or <cstring>) overloads many of the string functions.

So C has

char* strchr(const char*, int);

but C++ has

char* strchr(char*, int);
const char* strchr(const char*, int);

The C++ version is better because it preserves const correctness, but it not
available to C since it doesn't have function overloading.

In C one can write this

const char[] cs = "I'll not change, I'm const!";
char* p = strchr(cs, 'n'); // illegal in C++
strcpy(p, "may");
printf("%s\n", cs); // prints I may change, I'm const!

john


pablo

unread,
Jun 4, 2003, 4:47:18 AM6/4/03
to

would this line also work for tabs seperating it ? should I use \t for
the tab escape character.

p

Bowen

unread,
Jun 4, 2003, 1:00:09 PM6/4/03
to

I guess there's advantages and disadvantages to C users using a C++
compiler. Thanks. ;)

--
--Bowen--

John Harrison

unread,
Jun 4, 2003, 1:28:43 PM6/4/03
to
>
> > while (getline(buffer, word, ','))
> would this line also work for tabs seperating it ? should I use \t for
> the tab escape character.
>
> p

Yes it would. Yes you should.

john


Dietmar Kuehl

unread,
Jun 5, 2003, 8:03:22 AM6/5/03
to
"marane moll" <mar...@gmx.li> wrote:
> I'm programming with fstream and I want to read some comma-separated string
> values from file into the fitting variables (name, prename, age ...). Is
> there any fast way to do it?

Personally, I like the "whitespace redefinition approach" to this kind of
problem: Just make the stream think that the separating characters (eg.
comma and newline) are the only whitespaces. This is done by installing an
appropriate 'std::ctype<char>' facet into your 'std::istream' (or whatever
stream derived from this you are using). Here is an example:

#include <iostream>
#include <locale>
#include <algorithm>

struct commactype:
std::ctype<char>
{
commactype(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::ctype_base::mask* rc = 0;

if (rc == 0)
{
rc = new std::ctype_base::mask[std::ctype<char>::table_size];
std::fill_n(rc, std::ctype<char>::table_size,
std::ctype_base::mask());
rc[','] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
}
return rc;
}
};

int main()
{
std::string name, prename, age /* ... */;
std::cin.imbue(std::locale(std::locale(), new commactype));

while (std::cin >> name >> prename >> age /* ... */)
std::cout << "name: '" << name << "' "
<< "prename: '" << prename << "' "
<< "age: '" << age << "'\n";
}
--
<mailto:dietma...@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

John Harrison

unread,
Jun 5, 2003, 12:59:08 PM6/5/03
to

"Dietmar Kuehl" <dietma...@yahoo.com> wrote in message
news:5b15f8fd.03060...@posting.google.com...

Except that doesn't work as expected with repeated commas

abc,,def

Presumably the OP would want to read that as three strings not two.

john


Aaron Kincaid

unread,
Jun 5, 2003, 4:50:44 PM6/5/03
to
Thomas Matthews <tomat...@sbcglobal.net> wrote in message news:<3EDD2BE1...@sbcglobal.net>...

true. the poster didn't specify much, so i assumed they were a
beginner and kept my answer simple accordingly.

Dietmar Kuehl

unread,
Jun 6, 2003, 8:29:25 PM6/6/03
to
John Harrison wrote:
> Except that doesn't work as expected with repeated commas
>
> abc,,def
>
> Presumably the OP would want to read that as three strings not two.

Good point: I haven't thought of this. ... and it is, unfortunately,
not trivially removed by merely clearing the 'noskipws" flag
(eg. using 'std::cin >> std::noskipws') because this would leave the
separators in the stream. This also requires a little bit additional
stuff to extract the delimiter characters, too. Here is how this
could look like:

// facet and later installation of facet as before (omitted for
// brevity)
struct ignore_char {
ignore_char(char c): m_char(c) {}
char m_char;
};
ignore_char const comma(',');
ignore_char const newline('\n');

std::istream& operator>> (std::istream& in, ignore_char const& ic) {
if (!in.eof())
in.clear(in.rdstate() & ~std::ios_base::failbit);
if (in.get() != ic.m_char)
in.setstate(std::ios_base::failbit);
return in;
}

// ....
std::cin >> std::noskipws;
while (std::cin >> name >> comma >> prename >> age >> newline)
std::cout << "(" << name << ", " << prename << ", " << age << ")\n";

0 new messages