How to pass a struct to a function

B

Bill

Hello All,

I am trying to pass a struct to a function. How would that best be
accomplished?

Thanks,

Bill
 
C

Chris Dollin

Bill said:
I am trying to pass a struct to a function. How would that best be
accomplished?

Assuming that the function has an argument of the right structure type,
write an expression evaluating to your struct -- the name of a variable
of that struct type is popular -- in the appropriate argument position
in a call to that function.

What am I missing?

--
The second Jena users conference -- be there or have rdf:type geometric:Square.
"What I don't understand is this ..." Trevor Chaplin, /The Beiderbeck Affair/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
 
B

Bill

Assuming that the function has an argument of the right structure type,
write an expression evaluating to your struct -- the name of a variable
of that struct type is popular -- in the appropriate argument position
in a call to that function.

What am I missing?

--
The second Jena users conference -- be there or have rdf:type geometric:Square.
"What I don't understand is this ..." Trevor Chaplin, /The Beiderbeck Affair/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England

Here is what I have so far, won't even compile. And I am:

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

int AddEntry(struct entry);

struct{
char fName[51];
char lName[51];
char Phone[13];
}Entry;

int main()
{
int retCode;

Entry.fName = "Fred";
Entry.lName = "Flintstone";
Entry.Phone = "123-456-7890";

retCode = AddEntry(Entry);
}

//int AddEntry(char fName[51], char lName[51], char Phone[13])
int AddEntry(struct entry)
{
FILE *fp;

fp = fopen("AppData.dat", "a"); /* open file for writing */

fprintf(fp, "%s", fName); /* write some info */
fprintf(fp, "\t");
fprintf(fp, "%s", lName);
fprintf(fp, "\t");
fprintf(fp, "%s", Phone);
fprintf(fp, "\n");

fclose(fp); /* close the file */

return 1;
}
 
J

John Bode

Hello All,

I am trying to pass a struct to a function. How would that best be
accomplished?

Thanks,

Bill

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

/**
* Structure definition has to be visible to
* all functions that use it.
*/
struct foo {
int blah;
char blech[10];
double blurga;
};

/**
* Struct type passed by value.
*/
void printFoo(struct foo myStruct)
{
printf("%d, %s, %f\n", myStruct.blah, myStruct.blech,
myStruct.blurga);
}

/**
* Struct type passed by reference
*/
void printFooByRef(struct foo *myStruct)
{
printf("%d, %s, %f\n", myStruct->blah, myStruct->blech, myStruct-
}

int main(void)
{
struct foo theStruct;

theStruct.blah = 1;
strcpy(theStruct.blech, "ACK!");
theStruct.blurga = 3.14159;

printFoo(theStruct);
printFooByRef(&theStruct);

return 0;
}
 
R

Richard Heathfield

Bill said:

Here is what I have so far, won't even compile. And I am:

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

int AddEntry(struct entry);

struct{
char fName[51];
char lName[51];
char Phone[13];
}Entry;

You'll want to make this:

struct entry {
char fName[51];
char lName[51];
char Phone[13];
} Entry;

or, more clearly:

struct entry {
char fName[51];
char lName[51];
char Phone[13];
}; /* defines a type called 'struct entry' */

struct entry Entry; /* creates an object of that type */
 
M

Mr John FO Evans

"Bill" said:
I am trying to pass a struct to a function. How would that best be
accomplished?

The way I did it was as follows:-

a) define a type
typedef void (*FPOINT)(void)

b) define the structure including a pointer to the function to be called

typedef struct
{
.......

FPOINT simfunc; /* the function */

.....
.....
}function inst;

This way there can be as many functions as you like and as many different
instances as you like - all with different data.

When you call the function as follows:-

func-> simfunc()

The structured data goes with it.

John
 
K

Keith Thompson

Please don't quote signatures. Trim quoted material to what's
necessary for your followup to make sense to someone who hasn't see
the parent article.
Here is what I have so far, won't even compile. And I am:

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

Your program doesn't use anything from <string.h>, so this #include
directive is unnecessary. But, as we'll see, it *should*, so yes,
you'll need this #include directive.
int AddEntry(struct entry);

At this point, you haven't declared a type "struct entry". Because
it's an incomplete struct type, there are some interesting details
about how this declaration is handled, but that's not relevant; this
is not what you want, and you'll need to fix it.
struct{
char fName[51];
char lName[51];
char Phone[13];
}Entry;

Now you declare a struct object, but you *still* haven't declared a
type "struct entry". In fact, you don't declare "struct entry" (other
than as an incomplete type) anywhere in your program. What you've
done here is (a) declared an anonymous struct type, and (b) declared a
single object of that type, named "Entry". If all you want is a
single object, that might be sensible thing to do (or you might as
well declare the members as individual variables). But since you want
to pass it as an argument to a function, you should give the type a
name when you declare it.

Change the above declaration to:

struct entry {
char fName[51];
char lName[51];
char Phone[13];
};

and place it *above* the function declaration, so AddEntry knows what
a "struct entry" is. (More precisely, so the compiler knows what a
"struct entry" is when it processes the function declaration.)

(There's another common style that uses a typedef to give a structure
type a one-word name, but I won't get into that here.)

This creates a *named* type, called "struct entry". Note that it only
declares the type; unlike your original declaration, it doesn't
declare a variable of that type. I made that change because the
object (note: I'm using the terms "object" and "variable"
interchangeably) doesn't need to be global (more precisely, at file
scope). You can declare it inside the main() function.
int main()

Ok, but "int main(void)" is more explicit, and is preferred.
{
int retCode;

Add here:

struct entry Entry;

Though you might pick a more descriptive name than "Entry". In a real
program, you're probably going to have more than one object of that
type; each one should have a name that describes that object.
Entry.fName = "Fred";
Entry.lName = "Flintstone";
Entry.Phone = "123-456-7890";

If the members were char* pointers, you could do this, but you can't
assign to an array. Read section 6 of the comp.lang.c FAQ,
<http://www.c-faq.com/>. You can use the strcpy function here:

strcpy(Entry.fName, "Fred");
retCode = AddEntry(Entry);

You don't do anything with the value of retCode. That's ok in a small
sample program, but in a real program you'll probably want to do
something based on the result.

You should add "return 0;" before the closing brace of the main
function. It's not strictly required, but it's a good idea. You can
do more elaborate things if you want your program to report whether it
succeeded or failed.
}


//int AddEntry(char fName[51], char lName[51], char Phone[13])

It's best to avoid "//" comments when posting to Usenet. The C99
standard supports them, as do most exsting pre-C90 compilers (at least
in some mode), but they're not 100% portable. Also, Usenet software
commonly wraps long lines. Wrapping a "//" comment typically creates
a syntax error; a wrapped "/* ... */" comment typically is still a
valid comment.
int AddEntry(struct entry)

In a function declaration (without a body), you only need the types of
the parameters; the names are optional. In a function definition,
though, you have to provide names for the parameters, so the body of
the function can refer to them.

Let's call it "arg", for "argument":

int AddEntry(struct entry arg)
{
FILE *fp;

fp = fopen("AppData.dat", "a"); /* open file for writing */

You're opening the file for appending, not just writing. Either
mention that in the comment, or just drop the comment; any reader who
doesn't know what fopen() does is going to have bigger problems.
Comments like that are ok if you're trying to convince someone that
you know what you're doing, but they're not useful in providing actual
information to the reader.

You don't check whether the fopen() call succeeded. It returns a null
pointer (NULL) if it fails. Always check the result of fopen(), and
take some corrective action if it fails -- even if the corrective
action is to terminate the program with an error message.
fprintf(fp, "%s", fName); /* write some info */
fprintf(fp, "\t");
fprintf(fp, "%s", lName);
fprintf(fp, "\t");
fprintf(fp, "%s", Phone);
fprintf(fp, "\n");

The references to fName, lName, and Phone assume that they exist as
individual variables. They don't; they're members of a structure.
Now that that structure has been declared properly, you can refer to
them as arg.fName and so forth.

These six printf statements can be reduced to one:

fprintf(fp, "%s\t%s\t%s\n", arg.fName, arg.lName, arg.Phone);

fprintf() can fail. Combining the six printfs into one makes it
easier to check the result, and take some corrective action on
failure.
fclose(fp); /* close the file */

Another vacuous coment.

And fclose() can also fail. Consult the documentation for each of
these functions to find out how they indicate failure; it's different
for different functions.
return 1;

You always return the same value. If that's all you're going to do,
the function might as well not return a value at all (i.e., you can
declare it to return void rather than int). Or you can use the return
value to indicate to the caller whether the function succeeded or
failed. Decide how you want to do this, and *document* your
convention, for example in a comment associated with the function
declaration. One convention is to return 0 (false) for failure, 1
(true) for success. Another convention, since there are more ways to
fail than to succeed, is to return 0 for success, and some non-zero
value for failure; different values can indicate different kinds of
failure.

The values 51 and 13 are "magic numbers"; it's not at all clear what
they mean, or why you chose those particular values. Declare them as
constants, probably as preprocessor macros:

#define NAME_MAX 51
#define PHONE_MAX 13

Finally, you should learn to understand your compiler's diagnostic
messages (which you didn't show us). The details will vary depending
on which compiler you're using, but any decent compiler will print
messages that will tell an experienced programmer what the problem is,
though they may not always be obvious to a newbie. (They may not be
obvious to an experienced programmer if the compiler writer has
written poor messages, which does happen.)

*Before* you start correcting your code, compile it again, and pay
close attention to what your compiler tells you. If possible, set
options on your compiler to tell it to print lots of verbose warnings.
You'll probably find that your compiler's error and warning messages
will tell you just about everything about your code that I've just
told you, *if* you can understand how it's telling you. Take a look
at what your compiler tells you, and compare it to what I've told you
here.

Note that syntax errors can often confuse the compiler, and make some
of the following messages meaningless. A syntax error is, for
example, something like a missing semicolon or a mismatched
parenthesis. For other errors, like type mismatches, it's generally
easier for the compiler to recover and guess what you meant in the
following code. Fix the syntax errors first, so you can get better
messages for other errors. The very first error message the compiler
gives you is the most reliable; following messages may be the result
of the compiler's confusion.

(For gcc, "-ansi -pedantic -Wall -W -O3" is a good start. ("-O3"
enables optimization; a side effect is that the compiler performs more
analysis and can detect more problems in your code.) For other
compilers, check your documentation.)
 
C

CBFalconer

Bill said:
I am trying to pass a struct to a function. How would that best
be accomplished?

By naming some instance of the struct in the call to the function.
What's the problem?

struct foo blah = { whatever };

int foulupon(struct foo s) {
/* operate on s */
return something
}

....

if (foulupon(blah)) ...;
/* blah unchanged, becasue it was passed by value */
 
J

Jack Klein

The way I did it was as follows:-

a) define a type
typedef void (*FPOINT)(void)

Missing semicolon.
b) define the structure including a pointer to the function to be called

typedef struct
{
.......

FPOINT simfunc; /* the function */

.....
.....
}function inst;

Syntax error.
This way there can be as many functions as you like and as many different
instances as you like - all with different data.

When you call the function as follows:-

func-> simfunc()

The structured data goes with it.

NO data goes with it. You just called a function accepting no
arguments, passing no arguments to it.

If you know what you are talking about, try again to actually explain
it correctly.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
B

Bill Pursell

(There's another common style that uses a typedef to give a structure
type a one-word name, but I won't get into that here.)

Ack..I'll go into it. I used to always typedefs structs, and
in retrospect I believe it was simply because I didn't understand
the syntax well enough to realize it was unnecessary. Personally,
I find typedef'ing a struct to be a heinous act which should
NOT be done. Declarations of the form "FOO a;" are hardly
clearer than "struct foo a;", and it is impossible to tell
from "FOO a" whether a is a pointer or not--you need to
go look at the typedef. Sometimes it is appropriate to
typedef a struct, but usually it is not.

You're opening the file for appending, not just writing. Either
mention that in the comment, or just drop the comment; any reader who
doesn't know what fopen() does is going to have bigger problems.
Comments like that are ok if you're trying to convince someone that
you know what you're doing, but they're not useful in providing actual
information to the reader.

I disagree that such a comment is "OK". When I see
comments such as that, I tend to think that the
programmer in fact doesn't know what (s)he's doing.
If you happen to have a line of the form:
"data_fp[0] = fopen(data_path[4], "r");", then it would
be appropriate to add a comment explaining why
the fourth data file is being opened on the
zeroth file pointer, but completely pointless comments
serve to show a lack of knowledge on the part of
the programmer. Note that this should NOT serve
as a reason to avoid commenting your code. I have
often been very happy to see comments of the form:
/*
* I'm doing the following because I believe this will
* have this effect..., but I'm not entirely sure.
*/
(These are usually my own comments, BTW). When I
find comments like that, I know that the reason the code
looks a little weird is because the author was
in fact uncertain. There's nothing more annoying
than coming accross a section of arcane code that
you spend 40 hours analyzing only to discover that
it could have easily been re-written in 3 lines
and that all of the side-effects were in fact
totally unnecessary baggage that resulted from
a poor original design. Those 40 hours would
have been saved if a simple comment had been there
stating that the author was clueless and the
code should be redesigned from scratch.

Also annoying is the style which includes:
} /* end of i loop */
If your block is so large that you can't see the
opening brace, a comment doesn't fix the problem.
 
K

Keith Thompson

Bill Pursell said:
On 28 Mar, 22:49, Keith Thompson wrote an excellent article,
most of which I agree with, containing a few items on
which I'd like to comment: [...]
You're opening the file for appending, not just writing. Either
mention that in the comment, or just drop the comment; any reader who
doesn't know what fopen() does is going to have bigger problems.
Comments like that are ok if you're trying to convince someone that
you know what you're doing, but they're not useful in providing actual
information to the reader.

I disagree that such a comment is "OK". When I see
comments such as that, I tend to think that the
programmer in fact doesn't know what (s)he's doing.
If you happen to have a line of the form:
"data_fp[0] = fopen(data_path[4], "r");", then it would
be appropriate to add a comment explaining why
the fourth data file is being opened on the
zeroth file pointer, but completely pointless comments
serve to show a lack of knowledge on the part of
the programmer. Note that this should NOT serve
as a reason to avoid commenting your code.
[...]

Fair enough.

A context where an obvious comment might make a bit more sense is in
an introductory tutorial. For example, you might have something like:

fp = fopen("foobar.dat", "w") /* open file for writing */

the first time you introduce the fopen() function.
 
C

CBFalconer

Bill said:
.... snip ...

Also annoying is the style which includes:
} /* end of i loop */
If your block is so large that you can't see the
opening brace, a comment doesn't fix the problem.

I try to always annotate the closing '}' of a function with the
function name. This serves to make the demarcation between
functions obvious. I also add a specific interfunction demarcation
comment. E.g.:

int foo(...) {
...
} /* foo */

/* ------------------ */

char *bar(...) {
...

which I find enhances readability. I will annotate long loops with
?* while(foo) */ etc., although I agree that there is a strong
possibility it should call another routine.
 
B

Bill

Bill Pursell said:
On 28 Mar, 22:49, Keith Thompson wrote an excellent article,
most of which I agree with, containing a few items on
which I'd like to comment: [...]
fp = fopen("AppData.dat", "a"); /* open file for writing */
You're opening the file for appending, not just writing. Either
mention that in the comment, or just drop the comment; any reader who
doesn't know what fopen() does is going to have bigger problems.
Comments like that are ok if you're trying to convince someone that
you know what you're doing, but they're not useful in providing actual
information to the reader.
I disagree that such a comment is "OK". When I see
comments such as that, I tend to think that the
programmer in fact doesn't know what (s)he's doing.
If you happen to have a line of the form:
"data_fp[0] = fopen(data_path[4], "r");", then it would
be appropriate to add a comment explaining why
the fourth data file is being opened on the
zeroth file pointer, but completely pointless comments
serve to show a lack of knowledge on the part of
the programmer. Note that this should NOT serve
as a reason to avoid commenting your code.

[...]

Fair enough.

A context where an obvious comment might make a bit more sense is in
an introductory tutorial. For example, you might have something like:

fp = fopen("foobar.dat", "w") /* open file for writing */

the first time you introduce the fopen() function.

--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text -

- Show quoted text -

That is the case. I'm a programmer, but do not use C on a regular
basis. I'm a .Net guy. I got fingered for this gig and enjoy
teaching. But I also want to make sure I present quality info to
students. My professional code doesn't contain idiot comments. What
I ultimately present to students does get cleaned up. I was hoping I
could get some advice on a simple method to pass a struct to a
function. Thanks.
 
C

CBFalconer

Bill said:
.... snip ...

That is the case. I'm a programmer, but do not use C on a regular
basis. I'm a .Net guy. I got fingered for this gig and enjoy
teaching. But I also want to make sure I present quality info to
students. My professional code doesn't contain idiot comments.
What I ultimately present to students does get cleaned up. I was
hoping I could get some advice on a simple method to pass a struct
to a function. Thanks.

You did (get such advice). Just do it. My condolences on the .Net
lockin.
 
A

Al Balmer

That is the case. I'm a programmer, but do not use C on a regular
basis. I'm a .Net guy. I got fingered for this gig and enjoy
teaching. But I also want to make sure I present quality info to
students. My professional code doesn't contain idiot comments. What
I ultimately present to students does get cleaned up. I was hoping I
could get some advice on a simple method to pass a struct to a
function. Thanks.

Huh? What is the case? Are you commenting on Keith's signature block?
Your comments should be interspersed with properly trimmed quotes, and
signature blocks should not be quoted unless you're commenting on
them. See most of the other posts in this group for examples.

Using Google rather than a real news reader makes this more difficult,
but not impossible.
 
B

Ben Pfaff

CBFalconer said:
I try to always annotate the closing '}' of a function with the
function name. This serves to make the demarcation between
functions obvious.

Doesn't a closing brace at the left margin, on an otherwise blank
line, do the same thing? I would suspect that making the line
longer actually makes it harder to see the end of a function,
because then the form of the line is less distinct.
 
C

Chris Dollin

CBFalconer said:
I try to always annotate the closing '}' of a function with the
function name.

Folks is strange. But then, perhaps BCPL got it right with its
section brackets ...
This serves to make the demarcation between
functions obvious. I also add a specific interfunction demarcation
comment. E.g.:

The blank line isn't enough? Folks is ... no, I said that.
 
B

Beej Jorgensen

Chris Dollin said:
The blank line isn't enough? Folks is ... no, I said that.

I'm with Chuck on this one. There are blank lines all over the code.
While it is certainly possible to see the start of the function no
matter how much whitespace is about, having a horizontal comment in
there REALLY makes it stand out and, IMO, doesn't detract from
readability.

-Beej
 
B

Beej Jorgensen

Al Balmer said:
Huh? What is the case? Are you commenting on Keith's signature block?

Huh? What is what is the case? Are you commenting on Bill's
professional code or what he presents to students? ;)
Your comments should be interspersed with properly trimmed quotes

Indeed. :)
Using Google rather than a real news reader makes this more difficult,
but not impossible.

This has not been true for many months. Google Groups in its stock
configuration makes quoting as easy as it is with any other newsreader.
You click "Reply", and the properly-quoted text appears in an edit box
and your cursor is placed below it. In its current incarnation, it's a
perfectly "real" newsreader. Any time I'm on the road and don't have my
..newsrc file handy, I use it no-qualms.

-Beej
 
A

Al Balmer

Huh? What is what is the case? Are you commenting on Bill's
professional code or what he presents to students? ;)

Did you trim the part I replied to for the sole purpose of making the
above remark seem sensible?
 

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,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top