Reputation: 1920
I have a three row input file. First row is an int, the second row is ints with space, the third row is a string.
I have to scan them than manipulate the string based on the ints.
My problem is that I can scan the ints, but scanning the string causes segmentation fault at fclose.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE* in = fopen("be.txt", "r");
FILE* out = fopen("ki.txt", "w");
if(in==NULL){
printf("Error opening in!\n");
return -1;
}
if(out==NULL){
printf("Error opening out!\n");
return -1;
}
int brknglength, i;
fscanf(in, "%d", &brknglength);
printf("%d\n", brknglength);
int* seed[brknglength];
seed[brknglength] = malloc(sizeof(int[brknglength]));
for(i = 0; i < brknglength; i++){
if (fscanf(in, "%d", &seed[i]) != 1) {
printf("%d", i);
}
printf("%d.: %d \n", i, seed[i]);
}
char string;
fscanf(in, "%s", &string);
free(seed[brknglength]);
fclose(in);
fclose(out);
return 0;
}
What causes the segmentation fault?
Upvotes: 1
Views: 584
Reputation: 345
Your first Problem appears here:
int* seed[brknglength];
This defines an array of int
pointers on the stack.
seed[brknglength] = malloc(sizeof(int[brknglength]));
This initializes the element behind the array and overwrites your stack. To fix it, use either:
int seed[brknglength]; /* use without free(seed) */
or:
int *seed = malloc(sizeof(int[brknglength]));
/* ... */
free(seed);
The latter also works for compilers, which do not support variable length arrays.
Your second problem is reading a string into a single char
variable, which also overwrites the stack. Try something like:
char string[100];
fscanf(in, "%99s", &string);
Be aware, that "%s"
stops at whitespace. Use something like "%99[^\t\n]"
to define your own separators, or "%99c"
for a fixed length string.
The GNU Compiler offers the modifier "m"
(=allocate memory) as a convenient non-standard extension for all these cases:
char *string;
fscanf(in, "%ms", &string);
/* ... */
free(string);
Upvotes: 2
Reputation: 222323
int* seed[brknglength];
seed[brknglength] = malloc(sizeof(int[brknglength]));
It looks like what you tried to do here is make seed
a pointer to an array of int
and allocate space for it. However, that is the wrong syntax. Because [ ]
has higher precedence than *
, int* seed[brknglength];
defines an array of pointers to int
. Also, the name of the object is seed
, not seed[brknglength]
, so you would assign a value to it with seed = …
, not with seed[brknglength] = …
.
To make a pointer to an array and allocate space for it, use:
int (*seed)[brknglength];
seed = malloc(sizeof *seed);
Those can be combined (which is not a violation of the above note about using seed =
for assignment—initialization has a special syntax):
int (*seed)[brknglength] = malloc(sizeof *seed);
However, you probably do not want that. If size
is a pointer to an array, then you have to use *seed
wherever you want to refer to the array. So fscanf(in, "%d", &seed[i])
would have to be fscanf(in, "%d", &(*seed)[i])
.
Instead of making seed
a pointer to an array, just make it a pointer to an int
, and allocate space for as many int
as you want:
int *seed = malloc(brknglength * sizeof *seed);
Then you can use seed[i]
for element i
of the array instead of having to use (*seed)[i]
.
char string;
That defines string
to be a single char
. But fscanf(in, "%s", &string);
reads as many characters as the input has until a white-space character. So you need to pass fscanf
a pointer to the first of many char
. You can either declare string
to be an array:
char string[100];
or a pointer to space that is allocated:
char *string = malloc(100 * sizeof *string);
Then you can use fscanf(in, "%s", string);
. Note that you do not want to pass &string
. That is the address of the array or of the pointer, depending on how you defined string
. You want to pass the address of the first character, which is &string[0]
, or, equivalently, string
. (If string
is an array, it is automatically converted in this expression to a pointer to its first element, so it is equivalent to &string[0]
.)
Note that fscanf
will read as many character as the input contains until a white-space character appears. That can exceed whatever size you provide for string
. So you need to ensure the input does not have too many characters or tell fscanf
to limit how much it reads, which you can do with:
fscanf(in, "%99s", string);
or:
int n = 99;
fscanf(in, "%*s", n, string);
Note that fscanf
should be told to read at most one character less than the space in string
because it needs to add a terminating null character.
To free these objects, use:
free(seed);
free(string); // (If defined as a pointer, not an array.)
Upvotes: 2