problems with chr[]

  • Thread starter Christian Christmann
  • Start date
C

Christian Christmann

Hi,

I want to read a file line by line and tokenize the content.
My code:
ifstream Configuration;
Configuration.open("config.cfg");

// assume that max. length of line in configuration file is 120
// characters
char buffer[120];
char *tokenPtr;

while ( !Configuration.eof() )
{
Configuration.getline( buffer, 120, '\n' );
// check whether line is not a comment or empty line or beginning
// with white space, if so skip
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' )
{
// begin tokenization of buffer
tokenPtr = strtok( buffer, " " );

// dealing with memory specifications
if ( strcmp( tokenPtr, "MEMORY_AREA:" ) == 0 )
{
// read first token
tokenPtr = strtok ( NULL, " " );
if ( tokenPtr != NULL )
{
...
}
}

// dealing with CPU specs
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}
}
}



My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped.
Also the second line beginning with MEMORY_AREA: is correctly
analyzed. But instead of skipping the third line (since its an white space)
I get a Segmentation fault. Why is that?

Thx
Chris
 
S

Steven T. Hatton

Christian said:
Hi,

I want to read a file line by line and tokenize the content.
My code:
ifstream Configuration;
Configuration.open("config.cfg");

// assume that max. length of line in configuration file is 120
// characters
char buffer[120];
char *tokenPtr;

while ( !Configuration.eof() )
{
Configuration.getline( buffer, 120, '\n' );
// check whether line is not a comment or empty line or beginning
// with white space, if so skip
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' )
{
// begin tokenization of buffer
tokenPtr = strtok( buffer, " " );

// dealing with memory specifications
if ( strcmp( tokenPtr, "MEMORY_AREA:" ) == 0 )
{
// read first token
tokenPtr = strtok ( NULL, " " );
if ( tokenPtr != NULL )
{
...
}
}

// dealing with CPU specs
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}
}
}



My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped.
Also the second line beginning with MEMORY_AREA: is correctly
analyzed. But instead of skipping the third line (since its an white
space) I get a Segmentation fault. Why is that?

Thx
Chris

May I suggestion you use a debugger and trace the execution?
 
S

Steven T. Hatton

Christian said:
Hi,

I want to read a file line by line and tokenize the content.
My code:
ifstream Configuration;
Configuration.open("config.cfg");

// assume that max. length of line in configuration file is 120
// characters
char buffer[120];
char *tokenPtr;

while ( !Configuration.eof() )
{
Configuration.getline( buffer, 120, '\n' );
// check whether line is not a comment or empty line or beginning
// with white space, if so skip
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' )
{
// begin tokenization of buffer
tokenPtr = strtok( buffer, " " );

// dealing with memory specifications
if ( strcmp( tokenPtr, "MEMORY_AREA:" ) == 0 )
{
// read first token
tokenPtr = strtok ( NULL, " " );
if ( tokenPtr != NULL )
{
...
}
}

// dealing with CPU specs
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}
}
}



My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped.
Also the second line beginning with MEMORY_AREA: is correctly
analyzed. But instead of skipping the third line (since its an white
space) I get a Segmentation fault. Why is that?

Thx
Chris

One other suggestion. Try representing your data as C++ class types (that
includes struct), and use C++ I/O, string and perhaps stringstream to read
in your tokens. I'm not proficient at the art myself, but I believe it is a
sill worth developing, and would probably improve your code.
 
R

Rolf Magnus

Christian said:
Hi,

I want to read a file line by line and tokenize the content.
My code:
ifstream Configuration;
Configuration.open("config.cfg");

// assume that max. length of line in configuration file is 120
// characters
char buffer[120];

Why not use std::string? Then you don't need to make such assumptions.
char *tokenPtr;

while ( !Configuration.eof() )

This is wrong. eof() will return true, _after_ you tried to read past the
end of the file. So the loop will be run once to often. Also what is if
there is an error during reading?
Instead of the above, combine this with the getline below and make it:

while (Configuration.getline( buffer, 120, '\n' ))

For more about this, see the FAQ.
{
Configuration.getline( buffer, 120, '\n' );
// check whether line is not a comment or empty line or beginning
// with white space, if so skip
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' )

A '\n' will never be in there, since getline does not put it into the
buffer.
{
// begin tokenization of buffer
tokenPtr = strtok( buffer, " " );

// dealing with memory specifications
if ( strcmp( tokenPtr, "MEMORY_AREA:" ) == 0 )
{
// read first token
tokenPtr = strtok ( NULL, " " );
if ( tokenPtr != NULL )
{
...
}
}

// dealing with CPU specs
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}
}
}



My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped.
Also the second line beginning with MEMORY_AREA: is correctly
analyzed. But instead of skipping the third line (since its an white
space) I get a Segmentation fault. Why is that?

Because that line is empty, but your if() above doesn't count it as one.
Then, your first strtok will return a null pointer, which you subsequently
use in strcmp. This is probably what causes the segfault.
 
C

Christian Christmann

Why not use std::string? Then you don't need to make such assumptions.

Thank you for your answer. But it seems that getline is not accepting
strings as parameter.
My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped. Also
the second line beginning with MEMORY_AREA: is correctly analyzed. But
instead of skipping the third line (since its an white space) I get a
Segmentation fault. Why is that?

Because that line is empty, but your if() above doesn't count it as one.
Then, your first strtok will return a null pointer, which you subsequently
use in strcmp. This is probably what causes the segfault.

If added an if() to detect the empty line:
[...]
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}

else if (strcmp(tokenPtr, " ") == 0)
cout << "\nempty\n";

But this cout is never executed.
Why?

Chris
 
C

Christian Christmann

if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' ) {

I also just figured out that this if() is always true even if the line
begins with an #.
Why is the first character of buffer which represents the first
char of a new line not recognized as # ?

Chris
 
J

Jakob Bieling

Christian Christmann said:
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' ) {

I also just figured out that this if() is always true even if the line
begins with an #.
Why is the first character of buffer which represents the first
char of a new line not recognized as # ?


Think about it: the if statement will be true, if the first char is
not #, or if it is not \n. Now invert that and you get: the if statement
will be false, if the first char is # and if the first char is \n.
Because one char can never be two values at the same time, the if
statement will never be false, thus it will always be true.
Solution: replace the || with &&, because you do not want it to be #
*and* you do not want it to be \n either.

hth
 
R

Rolf Magnus

Christian said:
Thank you for your answer. But it seems that getline is not accepting
strings as parameter.

You're using the wrong getline. The one that takes std::string as parameter
is not a member of the stream. Try std::getline(thestream, thestring).
My config file look something like:
# Memory specs
MEMORY_AREA: 0x2000000 0x3000000

CPU: 150
[...]

When reading the file the first line with # is correctly skipped. Also
the second line beginning with MEMORY_AREA: is correctly analyzed. But
instead of skipping the third line (since its an white space) I get a
Segmentation fault. Why is that?

Because that line is empty, but your if() above doesn't count it as one.
Then, your first strtok will return a null pointer, which you
subsequently use in strcmp. This is probably what causes the segfault.

If added an if() to detect the empty line:
[...]
else if ( strcmp( tokenPtr, "CPU:" ) == 0 )
{
// read first token
}

else if (strcmp(tokenPtr, " ") == 0)
cout << "\nempty\n";

But this cout is never executed.
Why?

Because you are comparing your line with a line that contains a space
character, not with an empty line. Note that a space character is - even
thought not visible - a character and does not count as nothing.
 
R

Rolf Magnus

Christian said:
if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' ) {

I also just figured out that this if() is always true even if the line
begins with an #.
Why is the first character of buffer which represents the first
char of a new line not recognized as # ?

It is. But it's not at the same time a newline and a space charater. Your
condition will only be false if the first character is a #, a newline and a
space at the same time, which is of course not possible.
Check your logic.
 
A

ambar.shome

Dear Chris,
I tested your program and I found your logic to be incorrect. I think

"if ( buffer[0] != '#' || buffer[0] != '\n' || buffer[0] != ' ' ) "

this line should be

"if ( buffer[0] != '#' && buffer[0] != '\n' && buffer[0] != ' ' )"
..
Once I changed the above mentioned line your program worked fine.

Pls revert back if you have any questions.

Thanks & Regards
Ambar
 
A

Amadeus W. M.

This should be the structure of your parser, with the appropriate C++
tools. No need for strtok, it's cumbersome.

#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <string>


using namespace std;

// g++ -o parse parse.C
// ./parse config.cfg
int main(int argc, char * argv[])
{
string line, token;
fstream in(argv[1], ios::in); // argv[1]=config.cfg

do{
// Get the line.
getline(in, line);

// Parse it.
istringstream instr(line); // put it into a stringstream
while(instr >> token){ // extract 1 token at the time.

cerr << token << endl; // see what did.

// process token

}
}while(!in.eof());

in.close();

return 0;
}
 
S

Steven T. Hatton

Amadeus W. M. wrote:

[...]
}while(!in.eof());

in.close();

return 0;
}
According to what I just read in TC++SL §13.9, there is no need to
explicitly close a file when using fstream if you leave the scope without
trying to use it again. The destructor on fsteam will do that for you.

http://www.josuttis.com/libbook/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top