Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Bizarre segmentation fault involving i/o of data 2

Status
Not open for further replies.

WebDrake

Programmer
Sep 29, 2005
106
PL
As per my previous thread I went away and came up with a set of functions to help with data input. Unfortunately a segmentation fault is now showing up, apparently due to one of these functions, and I can't work out why.

Here's the code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <joealloc.h>

#define MAXLINESIZE 2*BUFSIZ

char *readLINE(void) {
	unsigned int linesize = 0;
	char query[BUFSIZ],*line = NULL,*check;
	
	do {
		fgets(query,BUFSIZ,stdin);
		check = strchr(query,'\n');
		if(check)
			*check = '\0';
		linesize += strlen(query);
		if(linesize < MAXLINESIZE) {
			if(linesize>strlen(query)) {
				REALLOC(line,line,linesize," REALLOC in readLINE in joeio.c");
				strcat(line,query);
			} else {
				MALLOC(line,linesize," MALLOC in readLINE in joeio.c");
				strcpy(line,query);
			}
		}
	} while(check==NULL);
	
	return line;
}


char *getSTRING(const unsigned int STRINGLENGTH) {
	char query[BUFSIZ], *s, *check;
	
	MALLOC(s,STRINGLENGTH," MALLOC in getSTRING in joeio.c");
	fgets(s,STRINGLENGTH,stdin);
	check = strchr(s,'\n');
	if(check)
		*check = '\0';
	else do {
		fgets(query,BUFSIZ,stdin);
		check = strchr(query,'\n');
	} while(check==NULL);
	
	return s;
}


char getCHAR(void) {
	char c = getchar(),d = getchar();
	while(d!='\n')
		d = getchar();
	return c;
}


int getINT(void) {
	int i;
	char *input = readLINE();
	sscanf(input,"%d",&i);
	free(input);
	return i;
}


double getDOUBLE(void) {
	double x;
	char *input = readLINE();
	sscanf(input,"%le",&x);
	free(input);
	return x;
}

(FYI, [tt]MALLOC[/tt] and [tt]REALLOC[/tt] refer to functions I wrote to make memory allocation safer. I don't think the problem is with them.)

The problem appears to be a result of using the [tt]getDOUBLE()[/tt] function. The aim here is that if someone types more than one number (or a number followed by anything else) just the first number will be registered by the program.

What appears to happen is that if I call [tt]getDOUBLE()[/tt] and, in entering input type something of the form

[tt]number otherstuff[/tt]

Where [tt]number[/tt] is a double (e.g. 1.35) and [tt]otherstuff[/tt] can be literally anything, then the following happens: if the total number of characters entered is exactly 20, then the program falls over. This can be prevented if I comment out the [tt]free()[/tt] command in [tt]getDOUBLE()[/tt].

I'm really quite stuck as to why this should happen, and why it should be so specific in when it occurs---it doesn't happen with getINT(), and it only happens with getDOUBLE() in the specific circumstance of entering exactly 20 characters.

Any ideas?
 
I think you should be mallocing/reallocing (linesize + 1) because of the null terminator of the strings.
 
1. fgets returns NULL on error or EOF - where is a test of these cases? No input buffer initialization in these cases and you have a garbage in s referenced memory...
2. Suppose no end-of-line chars (\n or \r\n) in the last line of input file. What's a stop condition for input loop in that case? check==NULL forever...

 
cpjust said:
I think you should be mallocing/reallocing (linesize + 1) because of the null terminator of the strings.
Bingo. I knew it must be something simple.

ArkM said:
2. Suppose no end-of-line chars (\n or \r\n) in the last line of input file. What's a stop condition for input loop in that case? check==NULL forever...
As I understand it [tt]fgets()[/tt] doesn't even begin to read from stdin until after the enter key has been pressed. I've tested it with a redefined, much shorter [tt]BUFSIZ[/tt] and I can type ad nauseum even with a loop exit condition in place.
 
ArkM said:
1. fgets returns NULL on error or EOF - where is a test of these cases? No input buffer initialization in these cases and you have a garbage in s referenced memory...
2. Suppose no end-of-line chars (\n or \r\n) in the last line of input file. What's a stop condition for input loop in that case? check==NULL forever...
Aaahhh, I think I see what you're getting at now. The loop works if you're just checking stdin (which is all it does right now), but if I expanded it to work with arbitrary files it would not work because of the errors you cite.

I guess the best way round it would be to exit also if fgets returns NULL; e.g. to rewrite the code as,

Code:
char *readLINE(void) {
	unsigned int linesize = 0;
	char query[BUFSIZ],*line = NULL,*check = NULL;
	
	while((fgets(query,BUFSIZ,stdin) != NULL) && (check==NULL)) {
		check = strchr(query,'\n');
		if(check)
			*check = '\0';
		linesize += strlen(query);
		if(linesize < MAXLINESIZE) {
			if(linesize>strlen(query)) {
				/* realloc to linesize+1 to take account of end character '\0' */
				REALLOC(line,line,linesize+1," REALLOC in readLINE in joeio.c");
				strcat(line,query);
			} else {
				/* malloc to linesize+1 to take account of end character '\0' */
				MALLOC(line,linesize+1," MALLOC in readLINE in joeio.c");
				strcpy(line,query);
			}
		}
	}
	
	return line;
}

... ?

Thanks very much cpjust and ArkM for the useful advice! :)
 
Whoops. Should reverse the order of checking in the while() section:
Code:
while((check==NULL) && (fgets(query,BUFSIZ,stdin) != NULL))
 
You (or user) may close stdin from the console (Ctrl-Z on Windows, for example) so EOF test is valid for console stdin too (not for redirected files only).
The case w/o \n at the last line is for redirected files, I agree...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top