Structures, Pointer and gets

R

Riaan Cillié

Hi

I'm trying to learn C, but I am struggling with using scanf and a struct. I
want to define a structure and declare a variable of that type in int main.
This has to be passed to a function and its values have to read and returned
from this function. How do you use gets() for this? I just can't figure it
out.

Here is a bit of code

typedef struct sStudent
{
char *Name;
char *ID;
} tStudent;

void ReadStudents(tStudent student[10])

int main()
{
tStudent student[10];
ReadStudents(student);
}

void ReadStudents(tStudent student[10])
{
????????????
}
 
R

RAiN

Well first if you want something to be sent back your function mustnt be
void or you can use it void but call by reference (pass the address)
Cause as you probably know if you pass a variable by value, it creates a
copy which dies at the end of the called function itself: so or return value
or work on the address.

Second, in the ReadStudent prototype you should declare an array of 10
elements. Arrays are just pointers for C. When you pass an array to a
function in the end you just pass the location memory of the first element,
then you access to the others with pointers arithmetics.


struct sStudent{
char *Name;
char *ID;
} tStudent[10];

typedef struct sStudent student; //sorry i hate typedef... :)


void ReadStudents(student *);

void ReadStudents(student *myStud){

printf("Plz insert your name: ");
gets(myStud->Name);
}
 
R

Richard Heathfield

Riaan said:
Hi

I'm trying to learn C, but I am struggling with using scanf and a struct.
I want to define a structure and declare a variable of that type in int
main. This has to be passed to a function and its values have to read and
returned from this function. How do you use gets() for this? I just can't
figure it out.

For a start, you don't use gets(). Ever. It has no way to protect your
buffer from being overrun with too much data.

Secondly, char * is not C-speak for "string". It is merely a pointer to a
character. It /can/ be used to point at the first of a bunch of characters
in a row, but it doesn't actually reserve any space itself. You must either
point it to valid space, or use a proper array instead. For now, let's use
an array:

Here is a bit of code

Great! Let's take a look...
typedef struct sStudent
{
char *Name;
char *ID;
} tStudent;

I suggest replacing this, for the time being, with:

#define NAME_LEN 32
#define ID_LEN 16

typedef struct sStudent
{
char Name[NAME_LEN];
char ID[ID_LEN];
} tStudent;
void ReadStudents(tStudent student[10])

int main()
{
tStudent student[10];
ReadStudents(student);
}

void ReadStudents(tStudent student[10])
{
????????????
}

Rather than lock the ReadStudents function down to a 10-element array, why
not pass in the size? This will entail changing the call, in main(), to:

ReadStudents(student, sizeof student / sizeof student[0]);

Here's a possible ReadStudents implementation. It's not completely robust,
but it will show you the general idea:

void ReadStudents(tStudent student[], size_t NumStudents)
{
size_t ThisStudent = 0;

while(ThisStudent < NumStudents)
{
puts("Please enter the student's name.");
fgets(student[ThisStudent].Name,
sizeof student[ThisStudent].Name,
stdin);
student[ThisStudent].Name[strlen(student[ThisStudent].Name) - 1] = '\0';
puts("Please enter the student's ID.");
fgets(student[ThisStudent].ID,
sizeof student[ThisStudent].ID,
stdin);
student[ThisStudent].ID[strlen(student[ThisStudent].ID) - 1] = '\0';
++ThisStudent;
}
}

Problems I haven't discussed:

1) fgets might fail (it returns NULL if it does).
2) User might type in more data than the buffer can hold. Unlike gets(),
fgets() will not allow this to overrun your buffer, but you will get
strange results on subsequent calls (because the remaining data will be
left in the buffer).
 
R

Richard Heathfield

RAiN said:
Well first if you want something to be sent back your function mustnt be
void or you can use it void but call by reference (pass the address)

There is no such thing as call by reference in C.

As it happens, he's using an array, so it's a moot point anyway (since the
name of an array decays into a pointer to its first element).
Cause as you probably know if you pass a variable by value, it creates a
copy which dies at the end of the called function itself: so or return
value or work on the address.

Second, in the ReadStudent prototype you should declare an array of 10
elements. Arrays are just pointers for C.

Not true. If it were true, arrays would have the same size as pointers, and
they don't (except by coincidence).
When you pass an array to a
function in the end you just pass the location memory of the first
element, then you access to the others with pointers arithmetics.

That, at least, is correct.

void ReadStudents(student *myStud){

printf("Plz insert your name: ");
gets(myStud->Name);
}

Undefined behaviour, guaranteed. Quite apart from using the gets() function
(which is severely broken), you forgot to reserve any storage for Name.
 
M

Mark McIntyre

Hi

I'm trying to learn C, but I am struggling with using scanf

scanf is quite a dangerous function for many reasons - I think the FAQ
talks about this. You would be better to use fgets, and then parse the
line you read in.
want to define a structure and declare a variable of that type in int main.
This has to be passed to a function and its values have to read and returned
from this function.

pass a pointer to the struct to your function doing the reading, read
in a value from stdin via fgets, convert the read in data from a
string to the right type for the struct element, and store.
How do you use gets() for this?

NEVER use gets. Its a bug waiting to happen. The FAQ definitely talks
about this.
I just can't figure it
out.

Here is a bit of code

typedef struct sStudent
{
char *Name;
char *ID;
} tStudent;

remember that ID and Name are only pointers to chars, with no memory
allocated. You will need to allocate memory for them as you go along.
It would be simpler to create them fixed-length, then hope you don't
get any students with very long names...

struct sStudent { char Name[128]; char ID[12]};
void ReadStudents(tStudent student[10])

int main()
{
tStudent student[10];

this creates an array of ten struct tStudents.
ReadStudents(student);

this passes the address of the first element to ReadStudents
void ReadStudents(tStudent student[10])
{
for i = 0 to 9
fgets some data
check its valid - for example names typically
don't begin with digits
copy it to Name
fgets some more data
validate that too - can IDs begin with letters?
copy it to ID
next loop
 
R

RAiN

Well first if you want something to be sent back your function mustnt be
There is no such thing as call by reference in C

passing by reference = a pointer to the original..
Sure isnt properly correct to talk of calll by reference in C but not even
Ritchie would kill you

Not true. If it were true, arrays would have the same size as pointers, and
they don't (except by coincidence).

Same here...
Arrays are treated by the machine as if they were pointers, this mean
myArray = *(myArray+i)

a little more flexibility man...

p.s. riaan the faster you get used to work using the pointers notation the
better it is
The more you advance the more you will find yourself working with them
 
A

Al Bowers

Riaan said:
Hi

I'm trying to learn C, but I am struggling with using scanf and a struct. I
want to define a structure and declare a variable of that type in int main.
This has to be passed to a function and its values have to read and returned
from this function. How do you use gets() for this? I just can't figure it
out.

Here is a bit of code

typedef struct sStudent
{
char *Name;
char *ID;
} tStudent;

void ReadStudents(tStudent student[10])

int main()
{
tStudent student[10];
ReadStudents(student);
}

void ReadStudents(tStudent student[10])
{
????????????
}

Unless you have allocated storage for struct members Name
and ID, they are simply char pointers without pointing
to any storage. To keep things simple you can change the members
from char * to char arrays.

typedef struct sStudent
{
char Name[32];
char ID[32];
} tStudent;

Change the function ReadStudents to:
void ReadStudents(tStudent *student);
and read in each student in a loop.

Do not use gets. It is very unsafe for user input. The
standard has other functions, such as fgets, that you
can safely use. Here is a example using function fgets.
It is just an demo and a really useful application would
not restrict the number of students in this way or
read the input data all in one chunk.

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

typedef struct sStudent
{
char Name[40];
char ID[32];
} tStudent;

void ReadStudent(tStudent *student);

int main(void)
{
tStudent MathClass[5];
int i;

for(i = 0; i < 5;i++)
{
ReadStudent(&MathClass);
putchar('\n');
}
puts("\nThe students in the Math Class are");
for(i = 0; i < 5;i++)
printf("\tName: %s\n\tID: %s\n\n",
MathClass.Name, MathClass.ID);
return 0;
}

void ReadStudent(tStudent *student)
{
char *s;

printf("Enter student name: ");
fflush(stdout);
fgets(student->Name,sizeof student->Name, stdin);
if((s = strchr(student->Name,'\n')) != NULL) *s = '\0';
else while(getchar() != '\n');
printf("Enter the Students ID: ");
fflush(stdout);
fgets(student->ID, sizeof student->ID, stdin);
if((s = strchr(student->ID,'\n')) != NULL) *s = '\0';
else while(getchar() != '\n');
return;
}
 
T

Thomas Stegen

RAiN said:
passing by reference = a pointer to the original..

Not so.
Sure isnt properly correct to talk of calll by reference in C but not even
Ritchie would kill you

Why not use correct terminology? There is a world of difference
between passing a reference by value and passing something by
reference. Understanding the terminology is the first step on the
way of understanding the issues involved.
Arrays are treated by the machine as if they were pointers, this mean
myArray = *(myArray+i)


So how this does not print the same number twice?

#include <stdio.h>

int main(void)
{
int arr[10];
int *ptr;
printf("%u %u\n"), (unsigned)sizeof arr, (unsigned)sizeof ptr);
return 0;
}

Arrays are converted to a pointer to the first element in the array
when they are evaluated for their value.
a little more flexibility man...

No, this is an important point.

Arrays are not just pointers. Consider arrays of arrays for example.
 
S

Sheldon Simms

passing by reference = a pointer to the original..
Sure isnt properly correct to talk of calll by reference in C but not even
Ritchie would kill you

Richard didn't "kill you" either. He just pointed out that there is
no call by reference in C. He is right. You are wrong. Deal with it.
Same here...
Arrays are treated by the machine as if they were pointers,

Sometimes they are. Sometimes they aren't. The C Standard says:

6.3.2.1#3
Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type array of type is converted to an expression
with type pointer to type that points to the initial element of the
array object and is not an lvalue.
a little more flexibility man...

Which do you prefer, flexible programs or correct programs?
 
J

Joe Wright

RAiN said:
passing by reference = a pointer to the original..
Sure isnt properly correct to talk of calll by reference in C but not even
Ritchie would kill you
Not really. Languages supporting call by reference don't do the pointer
stuff. The reference is the actual 'thing'. C doesn't do that and DMR
might actually kill you.
Not true. If it were true, arrays would have the same size as pointers, and
they don't (except by coincidence).

Same here...
Arrays are treated by the machine as if they were pointers, this mean
myArray = *(myArray+i)

Yes, but arrays are not pointers and pointers are not arrays. Right?
a little more flexibility man...

p.s. riaan the faster you get used to work using the pointers notation the
better it is
The more you advance the more you will find yourself working with them

Yes indeed. I am of the old school that differentiates between values
and objects. I read pointer as an object which may hold a value which is
the address of another object. Others call an address value a pointer. I
understand but I disagree.
 
T

Thomas Stegen

Joe said:
Yes indeed. I am of the old school that differentiates between values
and objects. I read pointer as an object which may hold a value which is
the address of another object. Others call an address value a pointer. I
understand but I disagree.

You disagree with a standard definition? Interesting... :)
 
M

Mark McIntyre

On Sat, 15 Nov 2003 17:39:04 GMT, in comp.lang.c , "RAiN"

(Someone else said)
passing by reference = a pointer to the original..

Thats not what "pass by reference" is generally taken to mean.
Consider C++. What C is doing is passing the value of a pointer.
Sure isnt properly correct to talk of calll by reference in C but not even
Ritchie would kill you

Its likely you'll confuse people, esp those familiar with C++ or other
languages that /do/ implement pass by reference.
Not true. If it were true, arrays would have the same size as pointers, and they don't (except by coincidence).

Arrays are treated by the machine as if they were pointers, this mean
myArray = *(myArray+i)


No. Accessing an array's elements is /equivalent/ to doing pointer
arithmetic but that doesn't make an array the same as a pointer.
Consider the result of sizeof, Consider the result of trying to free()
an array. Consider trying to assign to an array. The list goes on.
a little more flexibility man...

When you are correct, you get flexibility. When you're erroneous, you
don't... :-(
 
J

Joe Wright

Thomas said:
You disagree with a standard definition? Interesting... :)
Why interesting? Does the Standard confuse value and object? Maybe.
Let's examine two objects..

char arr[10];
char *arp;

I contend that arr is an array object and arp is a pointer object. Very
different things. Expressing arr yields the address of arr[0]. That
address can be assigned..

arp = arr;

Now you can use arr and arp interchangeably in most array contexts.
arr[5] == arp[5] will be true. But they are not the same. arr is an
array and arp is a pointer. Expressing either of them in rvalue context
will yield the same value but they are not the same things.
 
S

Sheldon Simms

Why interesting? Does the Standard confuse value and object?

Perhaps Thomas was thinking of 6.5.3.2

3 The unary & operator returns the address of its operand. If the
operand has type "TYPE", the result has type "pointer to TYPE".
 
T

Thomas Stegen

Joe said:
Why interesting?

Because the most you can say is that the definition is flawed.
A definition is, by definition, correct.
Does the Standard confuse value and object? Maybe.

It does not. Objects can have type pointer to T. Values can have type
pointer to T. Sheldon quoted an appropriate from the standard with which
you disagree (You are saying that the address of an object is not a
pointer.)
Let's examine two objects..

char arr[10];
char *arp;

As your example demonstrates something different from what you were
saying I snipped most of it.

You are saying (at least said) that arp is a pointer, whereas &arp is
not. Note that when arr is evaluated it is converted to a value which
is the address of the first element in the array. This value is not
stored in any object and so is by your disagreement with the standard
not a pointer. You just have to look at clause 6.3.2.1#2 to see that
this value is indeed a pointer.
 
J

Joe Wright

Thomas said:
Because the most you can say is that the definition is flawed.
A definition is, by definition, correct.


It does not. Objects can have type pointer to T. Values can have type
pointer to T. Sheldon quoted an appropriate from the standard with which
you disagree (You are saying that the address of an object is not a
pointer.)
I agree that both objects and values can have type 'pointer to T'.
Because a value has pointer type does not make it a pointer. From K&R2
the first sentence of Chapter 5: reads "A pointer is a variable that
contains the address of a variable." I know that K&R is not the Standard
but if Kernighan and Ritchie agree on something about C, it's good
enough for me.
Let's examine two objects..

char arr[10];
char *arp;

As your example demonstrates something different from what you were
saying I snipped most of it.

You are saying (at least said) that arp is a pointer, whereas &arp is
not. Note that when arr is evaluated it is converted to a value which
is the address of the first element in the array. This value is not
stored in any object and so is by your disagreement with the standard
not a pointer. You just have to look at clause 6.3.2.1#2 to see that
this value is indeed a pointer.
I'll 'say' it again for the listening impaired. A value is not a pointer
even if it has pointer type. The pointer is the object that holds the
value.

It's not just about pointers. Consider..

int a; /* a is an object of type int */

a = 5; /* 5 is a literal value of type int */

Although (a == 5) is true, 5 is not an object.

I've had this discussion before. It is clear as crystal to me. That
others can't see it as I do truly baffles me.
 
T

Thomas Stegen

Joe said:
Thomas Stegen wrote:

Pray tell. What is 'wrong' about anything I've said here?

"Others call an address value a pointer. I understand but I disagree."

I hope I never see you talking about a function returning pointers.
Oh and did you know that the unary & operator returns a pointer?
The standard is very clear on the matter.

If this is just your opinion please say so, because I am not
interested in discussing your opinion proper, which is what we
appear to be doing.
 
T

Thomas Stegen

Joe said:
Pray tell. What is 'wrong' about anything I've said here?

Ok, I've had a look at the standard and it does not define the
term "pointer" at all. So saying you disagree that the unary &
operator returns a pointer has no foundation anywhere. You even
disagree with K&R which states at least once that function
such and such returns a pointer to whatever. The standard also
does this. So the consensus between the standard and K&R is that
functions do return pointers. And the 2 other books I checked
also does this.

Also consider how awkward it is if only objects of type pointer
to T can be called pointer. You cannot say that a function takes
a pointer as an argument for example. It seems that pointer
should be used to mean anything (object or value) that has pointer
to T and if you want to make a distinction you use object of type
pointer to T or value of type pointer to T.

It certainly seems like the consensus is against you when the two
most authorative sources available on C programming is against you.
 

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,104
Messages
2,570,643
Members
47,247
Latest member
youngcoin

Latest Threads

Top