having problems with pointers (segmentation fault)

  • Thread starter damian birchler
  • Start date
D

damian birchler

If I run the following I get a segmentation fault:

#define NAMELEN 15
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) {
size_t i;
fgets(s, n+2, f);
i = strlen(s)-1;
if(s[(int)i] == '\n')
s[(int)i] = '\0';
return s;
}


int main(int argc, char *argv[]) {
int numOfPers;
pers_t pers[NPERS];
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");

/* initialize names for comparison */
for(i = 0; i < NPERS; i++)
bzero(pers.name, NAMELEN);

numOfPers = atoi(my_fgets(s, NAMELEN, in));
#ifdef DEBUG
printf("number of persons: %d\n", numOfPers);
my_fgets(pers[0].name, NAMELEN, in);
printf("person number 1 is %s\n", pers[0].name);
my_fgets(pers[1].name, NAMELEN, in);
printf("person number 2 is %s\n", pers[1].name);
#endif

for(i = 0; i < numOfPers; i++) {
my_fgets(pers.name, NAMELEN, in);
#ifdef DEBUG
printf("person number %d is %s", i+1, pers.name);
#endif
}

What seems so strange to me is that when I read the names in
'manually' it works perfectely, but when I try to read them in the for
loop the program crashes. I know that the error occurs in the for loop
because I won't see the result of the printf in the for loop. The
output is as follows:

number of persons: 5
person number 1 is dave
person number 2 is laura
Segmentation fault

Has anybody an idea of why this is?
Thanks
damian
 
K

Karthik Kumar

damian said:
If I run the following I get a segmentation fault:
You need two headers.

#include <stdio.h> /* FILE */
#include <stdlib.h> /* EXIT_SUCCESS */
#include said:
#define NAMELEN 15
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) {
size_t i;
fgets(s, n+2, f);
i = strlen(s)-1;
if(s[(int)i] == '\n')

Why are you casting it to 'int' ?
It is good to have the array indices to be of type 'size_t' .

s[(int)i] = '\0';

return s;
}


int main(int argc, char *argv[]) {
int numOfPers;
pers_t pers[NPERS];
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");

What if file open fails ?
/* initialize names for comparison */
for(i = 0; i < NPERS; i++)
bzero(pers.name, NAMELEN);

Please use memset with 0 instead of bzero .
bzero is non-standard.

memset(pers.name, 0, NAMELEN);
numOfPers = atoi(my_fgets(s, NAMELEN, in));
#ifdef DEBUG
printf("number of persons: %d\n", numOfPers);
my_fgets(pers[0].name, NAMELEN, in);
printf("person number 1 is %s\n", pers[0].name);
my_fgets(pers[1].name, NAMELEN, in);
printf("person number 2 is %s\n", pers[1].name);
#endif

In DEBUG mode, you have already read 2 persons' name.
for(i = 0; i < numOfPers; i++) {

#ifdef DEBUG
for(i = 0; i < numOfPers - 2; i++) {
#else
for(i = 0; i < numOfPers; i++) {
#endif

assuming you have read 2 persons' name before the loop.

my_fgets(pers.name, NAMELEN, in);
#ifdef DEBUG
printf("person number %d is %s", i+1, pers.name);
#endif
}

What seems so strange to me is that when I read the names in
'manually' it works perfectely, but when I try to read them in the for
loop the program crashes. I know that the error occurs in the for loop
because I won't see the result of the printf in the for loop. The
output is as follows:

number of persons: 5
person number 1 is dave
person number 2 is laura
Segmentation fault


My gift1.in looks as follows -

3
ADAM
BEN
CHRIS
DENNIS
ERIC


It worked for me.
 
J

j

If I run the following I get a segmentation fault:
#define NAMELEN 15
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) {

Change the type of ``n'' to ``size_t''.
If you have an fgets wrapper that relies on the size
of an object, then you want to be consistent with
the fgets function, which accepts the size of an object
as a size_t.
size_t i;
fgets(s, n+2, f);

And you pass NAMELEN to my_fgets, then you add
two here? Why? Do you realize what you are doing?
The size of the object is NAMELEN+1, so what is
this additional two for? You are lying to fgets about the
size. fgets can now read in one less than ``n+2'' bytes
starting from 0, so that is 17 bytes while ``name'' is 16 bytes.
i = strlen(s)-1;
if(s[(int)i] == '\n')

I want you to reply giving reasoning for this cast.
s[(int)i] = '\0';
Likewise.

return s;
}


int main(int argc, char *argv[]) {
int numOfPers;
pers_t pers[NPERS];
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");

You'll want to ensure that fopen did not fail,
so check if ``in'' is equal to NULL.
/* initialize names for comparison */
for(i = 0; i < NPERS; i++)

I don't see where ``i'' is declared.
bzero(pers.name, NAMELEN);


In this newsgroup, we discuss programming
under the c89/90 and c99 abstract machine,
which ``bzero'' is not a part of.

numOfPers = atoi(my_fgets(s, NAMELEN, in));

What do you think happens when ``my_fgets''
returns a string which represents an integer
value larger than what an int can portably represent?

Use strtol for error checking while changing the
type of ``numOfPers'' to long. When you do so,
you will also need to change the conversion
``%d'' to include the ``l''(That is, ELL) modifier.
So ``%ld''.
#ifdef DEBUG
printf("number of persons: %d\n", numOfPers);
my_fgets(pers[0].name, NAMELEN, in);
printf("person number 1 is %s\n", pers[0].name);
my_fgets(pers[1].name, NAMELEN, in);
printf("person number 2 is %s\n", pers[1].name);
#endif

for(i = 0; i < numOfPers; i++) {
my_fgets(pers.name, NAMELEN, in);
#ifdef DEBUG
printf("person number %d is %s", i+1, pers.name);
#endif
}


If DEBUG is defined, what do you think will happen
when your variadic function is called without a prototype
in scope?
 
M

Malcolm

damian birchler said:
If I run the following I get a segmentation fault:

#define NAMELEN 15
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
You can have a name of maximum NAMELEN characters.
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) {
size_t i;
fgets(s, n+2, f);
This is asking for trouble. First, you should check the return value.
Secondly, the length parameter gives the buffer size. By passing n+2, you
risk a memory overun of one.
i = strlen(s)-1;
if(s[(int)i] == '\n')
s[(int)i] = '\0';
The cast is unnecessary, and in fact disguises a problem. What if the call
to fgets() returns an empty string? You will attempt to read from s[-1],
which could be another segmentation fault.
return s;
}


int main(int argc, char *argv[]) {
int numOfPers;
pers_t pers[NPERS];
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");

/* initialize names for comparison */
for(i = 0; i < NPERS; i++)
bzero(pers.name, NAMELEN);

numOfPers = atoi(my_fgets(s, NAMELEN, in));
#ifdef DEBUG
printf("number of persons: %d\n", numOfPers);
my_fgets(pers[0].name, NAMELEN, in);
printf("person number 1 is %s\n", pers[0].name);
my_fgets(pers[1].name, NAMELEN, in);
printf("person number 2 is %s\n", pers[1].name);
#endif

for(i = 0; i < numOfPers; i++) {
my_fgets(pers.name, NAMELEN, in);
#ifdef DEBUG
printf("person number %d is %s", i+1, pers.name);
#endif
}

What seems so strange to me is that when I read the names in
'manually' it works perfectely, but when I try to read them in the for
loop the program crashes. I know that the error occurs in the for loop
because I won't see the result of the printf in the for loop. The
output is as follows:

number of persons: 5
person number 1 is dave
person number 2 is laura
Segmentation fault

Has anybody an idea of why this

A segmentation fault is caused by an undefined-behaviour read or write to
memory you do not own. Since the behaviour is undefined, seemingly unrelated
changes such as unrolling a for loop may cause the error to crop up in a
different place. This could be because you changed the memory layout of the
program internally.
 
M

Martin Ambuhl

damian said:
If I run the following I get a segmentation fault:

#define NAMELEN 15
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) {
size_t i;
fgets(s, n+2, f);
^^^
This is nuts. Since the size of the name member is NAMELEN+1, and
n==NAMELEN, it is insane to purposely ask for a buffer overrun.
pers_t pers[NPERS];
my_fgets(pers[0].name, NAMELEN, in);

Do yourself a favor, and make NAMELEN reflect the '\n\0' and stop
screwing around with inconsistent additions.
 
D

damian birchler

Ok. It was my fault. I wasn't exact enough. I'll try to fix that all
at once. This time I will post the whole program. The program is an
aproach to a problem at the IOI training program, so I'm not concerned
about malformed input (should I ?), nor am I concerned about faling
fopens (I wouldn't know how to react).

/*
ID: damian_1
PROG: gift1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define NAMELEN 15 /* extra space for newline */
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) { /* like fgets but without
newline */
fgets(s, (size_t)(n+1), f);
s[strlen(s)-1] = '\0';
return s;
}

int findPers(char *name, int numOfPers, pers_t *pers) {
int i;
for(i = 0; i < numOfPers; i++)
if(strcmp(name, pers.name) == 0)
return i;
}

int main(int argc, char *argv[]) {
int numOfPers;
int numOfGifts;
int initMoney;
int remainMoney;
int amount;
pers_t pers[NPERS];
int i;
int j;
char **ptr;
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");
FILE *out = fopen("gift1.out", "w");

/* initialize money */
for(i = 0; i < NPERS; i++)
pers.money = 0;

numOfPers = atoi(my_fgets(s, NAMELEN, in));

/* read in the persons' names */
for(i = 0; i < numOfPers; i++)
my_fgets(pers.name, NAMELEN, in);

/* for each person get its initial money, allot it and update it */
for(i = 0; i < numOfPers; i++) {
j = findPers(my_fgets(s, NAMELEN, in), numOfPers, pers);
initMoney = (int)strtol(my_fgets(s, NAMELEN, in), ptr, 0);
numOfGifts = (int)strtol(*ptr, NULL, 0);
remainMoney = initMoney % numOfGifts;
amount = (initMoney - remainMoney) / numOfGifts;
pers[j].money -= initMoney + remainMoney;
for(j = 0; j < numOfGifts; j++)
pers[findPers(my_fgets(s, NAMELEN, in), numOfPers,
pers)].money += amount;
}

/* print out solution */
for(i = 0; i < numOfPers; i++)
fprintf(out, "%s %d\n", pers.name, pers.money);

return 0;
}
 
B

Barry Schwarz

Ok. It was my fault. I wasn't exact enough. I'll try to fix that all
at once. This time I will post the whole program. The program is an
aproach to a problem at the IOI training program, so I'm not concerned
about malformed input (should I ?), nor am I concerned about faling
fopens (I wouldn't know how to react).

/*
ID: damian_1
PROG: gift1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define NAMELEN 15 /* extra space for newline */
#define NPERS 10

typedef struct pers {
char name[NAMELEN+1];
int money;
} pers_t;

char *my_fgets(char *s, int n, FILE *f) { /* like fgets but without
newline */
fgets(s, (size_t)(n+1), f);

The cast is unnecessary since the prototype is in scope.
s[strlen(s)-1] = '\0';

You have not checked to insure that the character about to be replaced
is in fact a '\n'. You could be replacing a valid character in the
name.
return s;
}

int findPers(char *name, int numOfPers, pers_t *pers) {
int i;
for(i = 0; i < numOfPers; i++)
if(strcmp(name, pers.name) == 0)
return i;


What happens if the name is not found. What do you return?
}

int main(int argc, char *argv[]) {
int numOfPers;
int numOfGifts;
int initMoney;
int remainMoney;
int amount;
pers_t pers[NPERS];
int i;
int j;
char **ptr;
char s[NAMELEN+1];
FILE *in = fopen("gift1.in", "r");

You never check if fopen succeeds.
FILE *out = fopen("gift1.out", "w");
Ditto.


/* initialize money */
for(i = 0; i < NPERS; i++)
pers.money = 0;

numOfPers = atoi(my_fgets(s, NAMELEN, in));


If the fopen failed, all the calls to my_fgets invoke undefined
behavior which can manifest as a seg fault.
/* read in the persons' names */
for(i = 0; i < numOfPers; i++)
my_fgets(pers.name, NAMELEN, in);

/* for each person get its initial money, allot it and update it */
for(i = 0; i < numOfPers; i++) {
j = findPers(my_fgets(s, NAMELEN, in), numOfPers, pers);
initMoney = (int)strtol(my_fgets(s, NAMELEN, in), ptr, 0);
numOfGifts = (int)strtol(*ptr, NULL, 0);
remainMoney = initMoney % numOfGifts;
amount = (initMoney - remainMoney) / numOfGifts;
pers[j].money -= initMoney + remainMoney;


If findPers failed, this would also invoke undefined behavior.
for(j = 0; j < numOfGifts; j++)
pers[findPers(my_fgets(s, NAMELEN, in), numOfPers,
pers)].money += amount;
}

/* print out solution */
for(i = 0; i < numOfPers; i++)
fprintf(out, "%s %d\n", pers.name, pers.money);


If the fopen failed, this also would invoke undefined behavior.
return 0;
}



<<Remove the del for email>>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top