l4zarus
asked on
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
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;
}
ASKER
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.
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.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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);
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);
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.