• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 817
  • Last Modified:

Why would fgets skip data?

I'm working on this code to read in an array of integers from a file, and I have it working for one test file, but I added another line to the array and for some reason when it has to read this extra line, fgets() seemingly "skips" over a few characters.

Attached is the function. This is the output I've been getting (the last line of the file, no different than any other line, has the numbers 5, 2, and 1. As shown by the sample output, doing a manual scan of the char *line that I read in shows that it somehow read in the 1 and a \n but "skipped" the first few characters...

Rows: 4
Cols: 3
Allocating 48 bytes for array...
'12     5       7
¿'
'12     5       7
'
'12'    Putting 12 in [(0 * 3 + 0) *4] = [0]
'5'     Putting 5 in [(0 * 3 + 1) *4] = [4]
'7'     Putting 7 in [(0 * 3 + 2) *4] = [8]
'8      16      2
¿'
'8      16      2
'
'8'     Putting 8 in [(1 * 3 + 0) *4] = [12]
'16'    Putting 16 in [(1 * 3 + 1) *4] = [16]
'2'     Putting 2 in [(1 * 3 + 2) *4] = [20]
'3      9       18
¿'
'3      9       18
'
'3'     Putting 3 in [(2 * 3 + 0) *4] = [24]
'9'     Putting 9 in [(2 * 3 + 1) *4] = [28]
'18'    Putting 18 in [(2 * 3 + 2) *4] = [32]
'       1
¿'
''
Rows: 4
Cols: 3

/*
getArrayFromFile
-----------------------
char *filename - pointer to the name of the matrix file to open.
int *rRows - pointer to allocated space to store the number of rows
int *rCols - pointer to allocated space to store the number of columns
*/
int *getArrayFromFile(char *filename, int *rRows, int *rCols)
{
	int *rows = malloc(sizeof(int));
	int *cols = malloc(sizeof(int));
	
	getFileInformation(filename, rows, cols);
	
	printf("Rows: %d\n", *rows);		//DEBUG
	printf("Cols: %d\n", *cols);		//DEBUG
	
	int bytesToAllocate = ((*rows)*(*cols)*sizeof(int));
	printf("Allocating %d bytes for array...\n",bytesToAllocate);
	
	int *A = malloc(bytesToAllocate*2);
	// Not sure why I'm multiplying it by 2... it allocated half of what I wanted.
	
	// ================ FILL ARRAY WITH NUMBERS ================
	
	FILE *file;
	file = fopen(filename, "r");
	if(file == NULL)
	{
		fprintf(stderr,"File could not be opened.");
		exit(1);
	}
	
	char *line = malloc(sizeof(char)*255);
	int col = 0, row = 0;
	
	//fgets(line,255,file);
	//while(!feof(file))
	while(fgets(line,255,file) != NULL)
	{
		int q = 0;
		printf("'");
		for(q = 0; q < 255; q++)
		{
			printf("%c",line[q]);
		}
		printf("'\n");
		
		printf("'%s'\n",line);		//DEBUG
		int i = 0;
		while(line[i] != '\n' && line[i] != '\0')
		{
			// Skip white space until we hit a number.
			while(line[i] == ' ' || line[i] == '\t')
			{
				i++;
			}
			
			// Reset number collector
			int numCount = 0;
			char num[10] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
			
			// Get number until we hit white space again.
			printf("'");	//DEBUG
			while(line[i] != ' ' && line[i] != '\t' && line[i] != '\n' && line != '\0')
			{
				printf("%c",line[i]);	//DEBUG
				num[numCount] = line[i];
				numCount++;
				i++;
			}
			printf("'\t");	//DEBUG
			
			int positionToPlace = (row * (*cols) + col)*sizeof(int);
			printf("Putting %d in [(%d * %d + %d) *%d] = [%d]\n",atoi(num),row,*cols,col,sizeof(int),positionToPlace);
			
			// We have number, put it in array
			A[positionToPlace] = atoi(num);

			col++;
			i++;
		}
		row++;
		col = 0; // Reset col in preparation for next row.
		
		//fgets(line,255,file);
	}
	
	free(line);
	fclose(file);
	
	// =========================================================
	
	*rRows = *rows;
	*rCols = *cols;
	
	free(rows);
	free(cols);
	
	return A;
}

Open in new window

0
l4zarus
Asked:
l4zarus
  • 2
  • 2
1 Solution
 
SordSordCommented:
Your manual scan of *line is not valid. The fgets function will put some number of characters in the memory pointed at by line, with the last character being a 0 value (null terminated). Your manual scan continues past that point and will show you characters that were not necessarily read by the fgets function.

The "printf("'%s'\n",line);" debug line indicates that you are not reading the last line at all. One possible reason might be that you have an end-of-file marker in the file and the last line is after that marker. That would cause fgets to stop reading before it got to your last line. A simple way to test it would be to create a new file and enter all four lines in at once to see how it changes the output.
0
 
l4zarusAuthor Commented:
By testing and messing around with things I've figured out that the problem comes down to
this line:
                      int positionToPlace = (row * (*cols) + col)*sizeof(int);
                       A[positionToPlace] = atoi(num);

Everything outputs correctly when I comment this line out. With it in, it skips or has skewed results with the last line. How does placing the number (no relation to *line) in to the array (no relation to *line) do anything to screw with.. *line.
0
 
l4zarusAuthor Commented:
Whole problem was caused by the *sizeof(int) - I was writing data ahead of the allocated array and probably into the line reads.
0
 
SordSordCommented:
It is a memory overwrite (probably writing over the FILE structure.  At the beginning you malloc some memory and assign it to and int pointer (in particular, you allocate 96 bytes of memory).

int *A = malloc(bytesToAllocate*2);

When you get to the "18'    Putting 18 in [(2 * 3 + 2) *4] = [32]" step, positionToPlace is 32, which would be fine if you were accessing the 32 byte in the buffer, but since A is an *int, when you reference A[32], it is the 32nd int value (or 32*4 = 128th byte).

You can fix the problem by not multiplying by the sizeof(int) since that will automatically happen with the A[] reference.

So change:
int positionToPlace = (row * (*cols) + col)*sizeof(int);
to
int positionToPlace = (row * (*cols) + col);
0

Featured Post

Live webcast with Pinal Dave

Pinal Dave will teach you tricks to help identify the real root cause of database problems rather than red herrings. Attendees will learn scripts that they can use in their environment to immediately figure out their performance Blame Shifters and fix them quickly.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now