Segmentation Fault...and we have no clue why

Exercise from book makes compiler give seg fault result

Page 1 of 1

8 Replies - 3168 Views - Last Post: 25 January 2009 - 03:18 PM Rate Topic: -----

#1 bytescribe   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 17-January 09

Segmentation Fault...and we have no clue why

Post icon  Posted 25 January 2009 - 09:21 AM

Hi, again, everyone.

My boyfriend and I have come upon another exercise in the C++ book we're using that has thrown us for a loop (no pun intended).

It's been a couple chapters in that book since I last posted, and we're now on Chapter 5, "Reading and Writing Files." The exercise we're stuck on is about formatting text with 'getline.'

When we compile and run the following code, we get a segmentation fault, with no core dump, but there is no real reason that we can see, why there should be a seg. fault. We're not using pointers...we're using a recursive loop that does have an end, so we're puzzled.

Here's the code.

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


int main()
{
	const int RANGE = 12;
	string tab[ RANGE ];
	int i = 0, j = 0;
	ifstream reader( "records.txt" );
	if( ! reader ){
		cout << "Error opening input file" << endl;
		return -1;
	}
	while( ! reader.eof() ) {
		if ( ( i + 1 ) % 4 == 0 )
				getline( reader, tab[ i++ ], '\n' );
		else
				getline( reader, tab[ i++ ], '\t' );
	}
	reader.close();
	i = 0;
	
	while( i < RANGE ){
		cout << endl << "Record Number: " << ++j << endl;
		cout << "Forename: " << tab[ i++ ] << endl;
		cout << "Surname: " << tab[ i++ ] << endl;
		cout << "Department: " << tab[ i++ ] << endl;
		cout << "Telephone: " << tab[ i++ ] << endl;
	}
	return 0;
}


Also, we're running Ubuntu Hardy Heron with, of course the GNU g-plus-plus compiler.

Any thoughts?

Laterz,
Kat ^.^

Is This A Good Question/Topic? 0
  • +

Replies To: Segmentation Fault...and we have no clue why

#2 bodom658   User is offline

  • Villiage Idiom
  • member icon

Reputation: 114
  • View blog
  • Posts: 1,123
  • Joined: 22-February 08

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 09:25 AM

is it possible that you had less or more than 12 people in the file?
Was This Post Helpful? 0
  • +
  • -

#3 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7268
  • View blog
  • Posts: 15,146
  • Joined: 16-October 07

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 09:43 AM

You have two possibilities for pain here. I'll comment them:
#include <fstream>
#include <string>
#include <iostream>

using namespace std;

int main() {
	const int RANGE = 12;
	string tab[ RANGE ];
	int i = 0, j = 0;
	
	ifstream reader( "records.txt" );
	if( ! reader ) {
		cout << "Error opening input file" << endl;
		return -1;
	}
	
	// here you're reading until EOF
	// but not checking if i>= RANGE
	// which will blow out your array
	while( ! reader.eof() ) {
		// I don't even want to know what's up with this
		// you'd be better off reading lines and going from there
		// have you looking into using vector?
		// arrays are SO C
		if ( ( i + 1 ) % 4 == 0 )
				getline( reader, tab[ i++ ], '\n' );
		else
				getline( reader, tab[ i++ ], '\t' );
	}
	reader.close();
	
	// huh?  You don't know how many lines you read
	// you might assume i==RANGE
	// reseting i to zero, you'll never know
	i = 0;
	
	// whoa, you're just asking for pain
	// suddenly you have j?  what does j mean?
	// how about record number?
	while( i < RANGE ){
		cout << endl << "Record Number: " << ++j << endl;
		cout << "Forename: " << tab[ i++ ] << endl;
		cout << "Surname: " << tab[ i++ ] << endl;
		cout << "Department: " << tab[ i++ ] << endl;
		cout << "Telephone: " << tab[ i++ ] << endl;
	}
	return 0;
}



Alright, you're reading some records. Break down the problem. Read in the entire line and then parse the line. It's tab delimited, shouldn't really be a big deal. Additionally, you have four fields in the record. Having a class or struct would be nice; no one likes magic array values.

Something like this might be nice:
typedef struct RecordStruct {
	string forename;
	string surname;
	string dept;
	string phone;
} RecordType;

void printRecord(RecordType &rec) {
	cout << "Forename: " << rec.forename << endl;
	cout << "Surname: " << rec.surname << endl;
	cout << "Department: " << rec.dept << endl;
	cout << "Telephone: " << rec.phone << endl;
}



Good luck.
Was This Post Helpful? 0
  • +
  • -

#4 bytescribe   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 17-January 09

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 11:54 AM

Hi again...

What you posted was working code. Helpful, but not what the exercise intended.

Here is the code again, with our comments on what we know, and don't know.
#include <fstream>
#include <string>
#include <iostream>
using namespace std;

/*We still don't entirely know what we are doing, so
 *please be patient :)
 *The comments may help you see where we are at
 *in our understanding with c++ and this exercise.
 */

/*The name of this exercise is "Formatting with getline"
 *this exercise is supposed show usage of arguments with
 *getline(), specifically how to make a delimiter to stop
 *reading a line
 */
int main()
{
	/*Here are the declarations which are easy enough
	 *to understand
	 */
	const int RANGE = 12;
	string tab[ RANGE ];
	int i = 0, j = 0;
	ifstream reader( "records.txt" );
	//We know what this if statement does
	if( ! reader ){
		cout << "Error opening input file" << endl;
		return -1;
	}
	/*This 'while' (according to the tutorial book we bought)
	 *is supposed to demonstrate the usage of two delimiters.
	 *One is \n and one is \t (new line and tab respectively)
	 *how this works is the line - 
	 *if ( ( i + 1 ) % 4 == 0 ) - checks to see if
	 *the remainder of i plus one divided by four equals zero. 
	 *if it does we get tab strings that delimit at the new line
	 *else we get tab strings that delimit at tabs
	 *(there are some assumptions made here)
	 */
	while( ! reader.eof() ) {
		if ( ( i + 1 ) % 4 == 0 )/*Here we had changed the modulus 
			 					  *to a division and got output but 
			 					  *wrongly formatted.
			 					  */
				getline( reader, tab[ i++ ], '\n' );
		else
				getline( reader, tab[ i++ ], '\t' );
	}
	reader.close();
	i = 0;
	/*This while prints out the separated results from
	 *the text file that was read. 
	 *We still don't know what the variable 'j' is for.
	 *Quentin has made a guess that 
	 *j increments while i is less than range.
	 */
	while( i < RANGE ){
		cout << endl << "Record Number: " << ++j << endl;
		cout << "Forename: " << tab[ i++ ] << endl;
		cout << "Surname: " << tab[ i++ ] << endl;
		cout << "Department: " << tab[ i++ ] << endl;
		cout << "Telephone: " << tab[ i++ ] << endl;
	}
	return 0;
/*The contents of the text file look like this
	 
John	Smith	Sales	555-1234
Mary	Jones	Wages	555-9876
Paul	Harris	Accts	555-4321
	 
*/
	
/*in the while statement we took out the modulus and used
	 a division symbol. The results printed are:
	 
Record Number: 1
Forename: John	Smith	Sales	555-1234
Surname: Mary	Jones	Wages	555-9876
Department: Paul	Harris	Accts	555-4321
Telephone: 

Record Number: 2
Forename: 
Surname: 
Department: 
Telephone: 

Record Number: 3
Forename: 
Surname: 
Department: 
Telephone: 
*/
}


Thanks again for helping!

Laterz,
Kat ^.^
Was This Post Helpful? 0
  • +
  • -

#5 buckrogers1965   User is offline

  • New Member

Reputation: 9
  • View blog
  • Posts: 87
  • Joined: 23-January 09

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 11:57 AM

View Postbytescribe, on 25 Jan, 2009 - 08:21 AM, said:

When we compile and run the following code, we get a segmentation fault, with no core dump, but there is no real reason that we can see, why there should be a seg. fault. We're not using pointers...we're using a recursive loop that does have an end, so we're puzzled.


This is why I love debuggers.

Compile your program with a -g flag, and drop the -O followed by a number flag from the gcc line. This compiles the executable with a lot more symbol information so it can work with the debugger better.

Then instead of running the bare executable, type:

gdb exec

Where exec is the name of the command you used to use to run the program. gdb stands for GNU debugger.

Then type run
at the prompt, press enter, and the program will run normally until it core dumps.

At that point type bt
for back trace and it will show the stack track with what line the exec was on at each level.

You can type up and down to move up and down the stack track and type print variable_name to examine a variable. You can type list
to see the code around the place the debugger is looking at the time.

At that same prompt you typed run at before you can also type:

break function_name

or

break line_number

Where function_name is the name of one of your functions, or line_number where that is a line number in your source code.

Then type run and the debugger will stop each time you hit that line number or call that function.

Type:

cont

or

step

to keep running from a break point. Step goes one line at a time, while cont just takes off running again.

Hope this helps. :)

This post has been edited by buckrogers1965: 25 January 2009 - 12:03 PM

Was This Post Helpful? 0
  • +
  • -

#6 bytescribe   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 17-January 09

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 12:33 PM

View Postbuckrogers1965, on 25 Jan, 2009 - 10:57 AM, said:

View Postbytescribe, on 25 Jan, 2009 - 08:21 AM, said:

When we compile and run the following code, we get a segmentation fault, with no core dump, but there is no real reason that we can see, why there should be a seg. fault. We're not using pointers...we're using a recursive loop that does have an end, so we're puzzled.


This is why I love debuggers.

Compile your program with a -g flag, and drop the -O followed by a number flag from the gcc line. This compiles the executable with a lot more symbol information so it can work with the debugger better.

Then instead of running the bare executable, type:

gdb exec

Where exec is the name of the command you used to use to run the program. gdb stands for GNU debugger.

Then type run
at the prompt, press enter, and the program will run normally until it core dumps.

At that point type bt
for back trace and it will show the stack track with what line the exec was on at each level.

You can type up and down to move up and down the stack track and type print variable_name to examine a variable. You can type list
to see the code around the place the debugger is looking at the time.

At that same prompt you typed run at before you can also type:

break function_name

or

break line_number

Where function_name is the name of one of your functions, or line_number where that is a line number in your source code.

Then type run and the debugger will stop each time you hit that line number or call that function.

Type:

cont

or

step

to keep running from a break point. Step goes one line at a time, while cont just takes off running again.

Hope this helps. :)


Hi BuckRogers!

Well, we tried running your idea, but we kept getting this:

/usr/bin/ld: cannot find -lgcc_s
collect2: ld returned 1 exit status


We run g-plus-plus as our compiler, not g c c. So I'm personally a little confused as to the instruction about "the number flag from the gcc line."
Was This Post Helpful? 0
  • +
  • -

#7 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7268
  • View blog
  • Posts: 15,146
  • Joined: 16-October 07

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 01:08 PM

This is your problem.
Record Number: 1
Forename: John	Smith	Sales	555-1234
Surname: Mary	Jones	Wages	555-9876
Department: Paul	Harris	Accts	555-4321
Telephone: 



Your example file has no tabs. So getline( reader, tab[ i++ ], '\t' ); just reads to the end and slurps up the whole thing. I like to use "~" as a delimiter, since the character is nonsensical on it's own, visible, and unlikely to be data.

While debuggers are ideal, you can do a lot in just your code to tell you what's going on.

Try this:
while( ! reader.eof() ) {
	if ( ( i + 1 ) % 4 == 0 )
		getline( reader, tab[i], '\n' );
	else
		getline( reader, tab[i], '\t' );
	cout << "read " << i << ":\t" << tab[i] << endl;
	i++;
}
reader.close();


You should get 0..11, yes? I bet you get 0..2. Put tabs in your file, or change the delimiter, and see how it goes.
Was This Post Helpful? 0
  • +
  • -

#8 bytescribe   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 17-January 09

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 01:50 PM

View Postbaavgai, on 25 Jan, 2009 - 12:08 PM, said:

This is your problem.
Record Number: 1
Forename: John	Smith	Sales	555-1234
Surname: Mary	Jones	Wages	555-9876
Department: Paul	Harris	Accts	555-4321
Telephone: 



Your example file has no tabs. So getline( reader, tab[ i++ ], '\t' ); just reads to the end and slurps up the whole thing. I like to use "~" as a delimiter, since the character is nonsensical on it's own, visible, and unlikely to be data.

While debuggers are ideal, you can do a lot in just your code to tell you what's going on.

Try this:
while( ! reader.eof() ) {
	if ( ( i + 1 ) % 4 == 0 )
		getline( reader, tab[i], '\n' );
	else
		getline( reader, tab[i], '\t' );
	cout << "read " << i << ":\t" << tab[i] << endl;
	i++;
}
reader.close();


You should get 0..11, yes? I bet you get 0..2. Put tabs in your file, or change the delimiter, and see how it goes.


baavgai--

Thanks for the little tip. We tried your idea and we got this result but still with a seg. fault no core dump:

read 0:	John
read 1:	Smith
read 2:	Sales
read 3:	555-1234
read 4:	Mary
read 5:	Jones
read 6:	Wages
read 7:	555-9876
read 8:	Paul
read 9:	Harris
read 10:	Accts
read 11:	555-4321
Segmentation fault




While the book we're using is good, overall, you guys' answers make me wonder about where the author is coming from.

A note, though: the author is writing for those who are using Windows, not Linux. He says that the exercises should work in Linux, but so far, one has not.
Was This Post Helpful? 0
  • +
  • -

#9 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7268
  • View blog
  • Posts: 15,146
  • Joined: 16-October 07

Re: Segmentation Fault...and we have no clue why

Posted 25 January 2009 - 03:18 PM

Right, I gave this one a spin with your original code. This will work if, and only if, your data file is three lines only and tab delimited. If you put a line feed after the third line, making a fourth line, you will crash as you read past the end of your array.

You can avoid this by putting an extra check into your while. e.g.
	while( i<RANGE && !reader.eof() ) {
		getline( reader, tab[i], (( i + 1 ) % 4 == 0) ? '\n' : '\t' );
		i++;
	}



If this code is yours, it's fine; you're learning.

However, if this comes for a book or something claiming to teach the basics of programming, it's not teaching you any good habits. Here's an example of how what you're doing might look in C++.

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

using namespace std;

typedef struct RecordStruct {
	string forename;
	string surname;
	string dept;
	string phone;
} RecordType;

typedef vector<RecordType> RecordCollection;

void show(RecordType &rec) {
	cout << "Forename: " << rec.forename << endl;
	cout << "Surname: " << rec.surname << endl;
	cout << "Department: " << rec.dept << endl;
	cout << "Telephone: " << rec.phone << endl;
}


void show(RecordCollection &rc) {
	int recNum = 0;
	RecordCollection::iterator it = rc.begin();
	for(;it!=rc.end(); ++it) {
		cout << endl << "record: " << ++recNum << endl; 
		show(*it);
	}
}


RecordType parseRecord(string &data) {
	static char delim = '\t';
	RecordType rec;
	
	stringstream ss(data);
	getline(ss, rec.forename, delim); 
	if (!getline(ss, rec.surname, delim)) { return rec; }
	if (!getline(ss, rec.dept, delim)) { return rec; }
	getline(ss, rec.phone, delim);
	return rec;
}


void loadRecordCollection(const char *fileName, RecordCollection &rc) {
	ifstream reader(fileName);
	if(!reader) {
		cout << "Error opening input file" << endl;
		return;
	}
	
	while( !reader.eof() ) {
		string line;
		getline( reader, line);
		RecordType rec = parseRecord(line);
		if (rec.forename.length() > 0) {
			rc.push_back( parseRecord(line) );
		}
	}
	reader.close();
}


int main() {
	RecordCollection rc;
	loadRecordCollection("records.txt", rc);
	show(rc);
	return 0;
}


Was This Post Helpful? 0
  • +
  • -

Page 1 of 1