Character Points/Structs/Input

J

Jeff Mott

Ok, here's the situation. I've got a file whose first line indicates
how many n number of names will follow. And some more data after that,
but I havn't gotten that far yet. So what I've got is...

1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: typedef struct {
5: char* name;
6: int initial_money_value;
7: int current_money_value;
8: } person;
9:
10: person* people;
11:
12: int main(void)
13: {
14: FILE* in = fopen("gift1.in", "r");
15:
16: int n_people;
17: fscanf(in, "%i", &n_people);
18:
19: people = (person*)calloc(n_people, sizeof(person));
20:
21: int i = 0;
22: for ( ; i < n_people; ++i) {
23: fscanf(in, "%s", people.name);
24: people.current_money_value = 0;
25: }
26: }

Unfortunately the program will crash at runtime, apparently at line
23. However, if I replace that last block of code with...

21: int i = 0;
22: char* nm;
23: for ( ; i < n_people; ++i) {
24: fscanf(in, "%s", nm);
25: people.name = nm;
26: people.current_money_value = 0;
27: }

Then this will work. So apparently there is some detail about either
strings or structs (or something related) that I'm missing. Why does
the first version crash?

Also, since I'm learning the language, if there are any good
programming practices that I have not followed, please alert me to
these as well.
 
E

Eric Sosman

Jeff said:
Ok, here's the situation. I've got a file whose first line indicates
how many n number of names will follow. And some more data after that,
but I havn't gotten that far yet. So what I've got is...

1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: typedef struct {
5: char* name;
6: int initial_money_value;
7: int current_money_value;
8: } person;
9:
10: person* people;
11:
12: int main(void)
13: {
14: FILE* in = fopen("gift1.in", "r");
15:
16: int n_people;
17: fscanf(in, "%i", &n_people);
18:
19: people = (person*)calloc(n_people, sizeof(person));
20:
21: int i = 0;
22: for ( ; i < n_people; ++i) {
23: fscanf(in, "%s", people.name);
24: people.current_money_value = 0;
25: }
26: }

Unfortunately the program will crash at runtime, apparently at line
23. However, if I replace that last block of code with...

21: int i = 0;
22: char* nm;
23: for ( ; i < n_people; ++i) {
24: fscanf(in, "%s", nm);
25: people.name = nm;
26: people.current_money_value = 0;
27: }

Then this will work. So apparently there is some detail about either
strings or structs (or something related) that I'm missing. Why does
the first version crash?


This is Question 7.1 in the comp.lang.c Frequently Asked
Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html
Also, since I'm learning the language, if there are any good
programming practices that I have not followed, please alert me to
these as well.

One highly recommended practice is to read the FAQ and to
ponder carefully any answers you find surprising or confusing.
It also has a bibliography, slightly dated perhaps but still a
good place to start.
 
J

Joe Wright

Jeff said:
Ok, here's the situation. I've got a file whose first line indicates
how many n number of names will follow. And some more data after that,
but I havn't gotten that far yet. So what I've got is...

1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: typedef struct {
5: char* name;
6: int initial_money_value;
7: int current_money_value;
8: } person;
9:
10: person* people;
11:
12: int main(void)
13: {
14: FILE* in = fopen("gift1.in", "r");
15:
16: int n_people;
17: fscanf(in, "%i", &n_people);
18:
19: people = (person*)calloc(n_people, sizeof(person));
20:
21: int i = 0;
22: for ( ; i < n_people; ++i) {
23: fscanf(in, "%s", people.name);
24: people.current_money_value = 0;
25: }
26: }

Unfortunately the program will crash at runtime, apparently at line
23. However, if I replace that last block of code with...

21: int i = 0;
22: char* nm;
23: for ( ; i < n_people; ++i) {
24: fscanf(in, "%s", nm);
25: people.name = nm;
26: people.current_money_value = 0;
27: }

Then this will work. So apparently there is some detail about either
strings or structs (or something related) that I'm missing. Why does
the first version crash?

Also, since I'm learning the language, if there are any good
programming practices that I have not followed, please alert me to
these as well.


Hi Jeff, I didn't try to compile you program because of the line
numbering. A cursory look at it seems that the various person.name
pointers are never initialized to point to memory.
 
A

Andrew Clark

(e-mail address removed) (Jeff Mott) wrote in

[...]
10: person* people;
[...]

26: people.current_money_value = 0;
27: }

[...]


Also, since I'm learning the language, if there are any good
programming practices that I have not followed, please alert me to
these as well.


Can you see the difference here?

a)

struct
{
int b;
char c;
}
a;

/* ... */
a.b = 42;
a.c = 'H';

b)

struct
{
int b;
char c;
}
*a;

/* ... */
a = malloc (sizeof *a);
/* assuming success */
a -> b = 42;
a -> c = 'H';
free (a); /* let it go, of course */

If you can find the inconsistency between a) and b), you'll have it.

This is not a programming practice, but a posting one: Don't include line
numbers. While they make it easier to identify problem lines, their
inclusion renders a posted program uncompilable. I personally wouldn't make
the effort to remove all those numbers to find out what my compiler would
tell me about this program.

Andrew
 
B

Barry Schwarz

Ok, here's the situation. I've got a file whose first line indicates
how many n number of names will follow. And some more data after that,
but I havn't gotten that far yet. So what I've got is...

1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: typedef struct {
5: char* name;
6: int initial_money_value;
7: int current_money_value;
8: } person;
9:
10: person* people;
11:
12: int main(void)
13: {
14: FILE* in = fopen("gift1.in", "r");
15:
16: int n_people;
17: fscanf(in, "%i", &n_people);
18:
19: people = (person*)calloc(n_people, sizeof(person));
20:
21: int i = 0;
22: for ( ; i < n_people; ++i) {
23: fscanf(in, "%s", people.name);
24: people.current_money_value = 0;
25: }
26: }

Unfortunately the program will crash at runtime, apparently at line
23. However, if I replace that last block of code with...


As well it should. You never initialize people.name to point to
valid memory. Passing the value of an uninitialized variable to a
function invokes undefined behavior. (Any attempt to evaluate an
uninitialized variable does so.) If that isn't bad enough, fscanf
will try to store something in the memory .name points to. Since it
doesn't point to memory you own (it doesn't point anywhere, it's value
is indeterminate), this also invokes undefined behavior.
21: int i = 0;
22: char* nm;
23: for ( ; i < n_people; ++i) {
24: fscanf(in, "%s", nm);
25: people.name = nm;
26: people.current_money_value = 0;
27: }

Then this will work. So apparently there is some detail about either
strings or structs (or something related) that I'm missing. Why does
the first version crash?


How does this improve the situation? You have substituted one
uninitialized pointer (nm) for another (.name). What you have is an
excellent example of why undefined behavior cannot be depended on to
behave in any predictable way. The first behavior is obviously more
user friendly since it informs you immediately that there is a
problem. The second is rather insidious because it leads you to
believe your code is correct when in fact it is just as broken.
Also, since I'm learning the language, if there are any good
programming practices that I have not followed, please alert me to
these as well.

Get rid of the line numbers when posting. People who are willing to
help (by compiling your code) don't need the extra work of removing
them.

It is OK to define an uninitialized variable (style debate aside) but
you must make sure that the variable is assigned a value before it is
referenced/evaluated.


<<Remove the del for email>>
 
M

Martin Ambuhl

Jeff said:
Ok, here's the situation. I've got a file whose first line indicates
how many n number of names will follow. And some more data after that,
but I havn't gotten that far yet. So what I've got is...

1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: typedef struct {
5: char* name;
6: int initial_money_value;
7: int current_money_value;
8: } person;
9:
10: person* people;
11:
12: int main(void)
13: {
14: FILE* in = fopen("gift1.in", "r");
15:
16: int n_people;
17: fscanf(in, "%i", &n_people);
18:
19: people = (person*)calloc(n_people, sizeof(person));
20:
21: int i = 0;
22: for ( ; i < n_people; ++i) {
23: fscanf(in, "%s", people.name);

^^^^^^^^^^^^^^^
You haven't allocated any space to which the pointer people.name
should point. Read the name into a buffer of an appropriately large
size (fgets is a better idea that fscanf, especially with that "%s"
specifier), find the length of the string, allocate space one larger
than that for people.name, and copy the string to that space.
 

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

No members online now.

Forum statistics

Threads
474,142
Messages
2,570,818
Members
47,362
Latest member
eitamoro

Latest Threads

Top