63

I'm a new C programmer and I wanted to know how I can pass a struct through to a function. I'm getting an error and can't figure out the correct syntax to do it. Here is the code for it....

Struct:

struct student{
    char firstname[30];
    char surname[30];
};

struct student person;

Call:

addStudent(person);

Prototype:

void addStudent(struct student);

and the actual function:

void addStudent(person)
{
    return;
}

Compiler errors:

line 21: warning: dubious tag declaration: struct student
line 223: argument #1 is incompatible with prototype:

Dalton Cézane
  • 3,672
  • 2
  • 35
  • 60
Daniel Del Core
  • 3,071
  • 13
  • 38
  • 52
  • 1
    Where are you declaring your struct? In your actual implementation file, where is your `struct student { /* ... */ };` code? It looks like it's in the wrong scope (like declared in your `main` function or whatever function you're trying to call `addStudent` from... – Jason Coco Apr 29 '12 at 06:04
  • yeah its in my function scope – Daniel Del Core Apr 29 '12 at 06:06

5 Answers5

129

This is how to pass the struct by reference. This means that your function can access the struct outside of the function and modify its values. You do this by passing a pointer to the structure to the function.

#include <stdio.h>
/* card structure definition */
struct card
{
    int face; // define pointer face
}; // end structure card

typedef struct card Card ;

/* prototype */
void passByReference(Card *c) ;

int main(void)
{
    Card c ;
    c.face = 1 ;
    Card *cptr = &c ; // pointer to Card c

    printf("The value of c before function passing = %d\n", c.face);
    printf("The value of cptr before function = %d\n",cptr->face);

    passByReference(cptr);

    printf("The value of c after function passing = %d\n", c.face);

    return 0 ; // successfully ran program
}

void passByReference(Card *c)
{
    c->face = 4;
}

This is how you pass the struct by value so that your function receives a copy of the struct and cannot access the exterior structure to modify it. By exterior I mean outside the function.

#include <stdio.h>


/* global card structure definition */
struct card
{
    int face ; // define pointer face
};// end structure card

typedef struct card Card ;

/* function prototypes */
void passByValue(Card c);

int main(void)
{
    Card c ;
    c.face = 1;

    printf("c.face before passByValue() = %d\n", c.face);

    passByValue(c);

    printf("c.face after passByValue() = %d\n",c.face);
    printf("As you can see the value of c did not change\n");
    printf("\nand the Card c inside the function has been destroyed"
        "\n(no longer in memory)");
}


void passByValue(Card c)
{
    c.face = 5;
}
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Donnell
  • 1,291
  • 2
  • 8
  • 2
  • concise. Pretty neat. – Raynal Gobel Dec 07 '15 at 05:43
  • Absolutely perfect ! – StrawHara Mar 24 '16 at 19:27
  • A bit late to ask, but why typedef the struct to the same name (but with a capital)? I'm also wondering why you need to create a pointer to the struct (`*cptr`), then use that to pass to the function, when you could pass the original card struct by reference using `&c`. I'm new to structs in C so genuinely looking for feedback. – Matt K Aug 04 '21 at 16:59
  • Neat code, excellent explanation. – Arjuna Deva Nov 17 '21 at 14:34
  • @MattK Typdefing to the same name would allow us to later define instances structs without the `struct` keyword. E.g. this example without the typedef: `struct card card1 = {...};`. With typedef: `card card1 = {...};`. The capital letter and the pointer creation both are just preference (convention/readability) AFAIK. – Wadite RK Feb 23 '22 at 20:31
50

The line function implementation should be:

void addStudent(struct student person) {

}

person is not a type but a variable, you cannot use it as the type of a function parameter.

Also, make sure your struct is defined before the prototype of the function addStudent as the prototype uses it.

MByD
  • 135,866
  • 28
  • 264
  • 277
  • 6
    A good idea is to "name" the struct type to avoid this problem, using typedef. See http://en.wikipedia.org/wiki/Struct_(C_programming_language) – Jouni Aro Apr 29 '12 at 05:58
  • does that mean i have to take the whole struct out of my function and put it in my header file where the prototypes are? – Daniel Del Core Apr 29 '12 at 06:04
  • @DanielDC - I was afraid to ask this. Yes, the struct should be declared in a global scope, as it is used by other functions as well. – MByD Apr 29 '12 at 06:06
  • ohk i thought you could just use it the same way as ints and chars. ;( how embarrassing... thanks for your help – Daniel Del Core Apr 29 '12 at 06:09
  • 1
    You welcome, don't take it too hard, it's not trivial when you start with the language. – MByD Apr 29 '12 at 06:10
  • What if I only want to access one member of that struct directly, do I still need to pass the entire struct to the function or could I specify the struct.member at definition? – Alan Jan 26 '16 at 13:39
  • **function(&mystruct.member);** seems to work ok. the function is defined with a pointer to the entire struct, though, like so: **void function( struct mystruct *);**. is this correct? – Alan Jan 26 '16 at 13:52
10

When passing a struct to another function, it would usually be better to do as Donnell suggested above and pass it by reference instead.

A very good reason for this is that it makes things easier if you want to make changes that will be reflected when you return to the function that created the instance of it.

Here is an example of the simplest way to do this:

#include <stdio.h>

typedef struct student {
    int age;
} student;

void addStudent(student *s) {
    /* Here we can use the arrow operator (->) to dereference 
       the pointer and access any of it's members: */
    s->age = 10;
}

int main(void) {

    student aStudent = {0};     /* create an instance of the student struct */
    addStudent(&aStudent);      /* pass a pointer to the instance */

    printf("%d", aStudent.age);

    return 0;
}

In this example, the argument for the addStudent() function is a pointer to an instance of a student struct - student *s. In main(), we create an instance of the student struct and then pass a reference to it to our addStudent() function using the reference operator (&).

In the addStudent() function we can make use of the arrow operator (->) to dereference the pointer, and access any of it's members (functionally equivalent to: (*s).age).

Any changes that we make in the addStudent() function will be reflected when we return to main(), because the pointer gave us a reference to where in the memory the instance of the student struct is being stored. This is illustrated by the printf(), which will output "10" in this example.

Had you not passed a reference, you would actually be working with a copy of the struct you passed in to the function, meaning that any changes would not be reflected when you return to main - unless you implemented a way of passing the new version of the struct back to main or something along those lines!

Although pointers may seem off-putting at first, once you get your head around how they work and why they are so handy they become second nature, and you wonder how you ever coped without them!

user2373145
  • 332
  • 2
  • 14
tom1990
  • 602
  • 8
  • 17
4

You need to specify a type on person:

void addStudent(struct student person) {
...
}

Also, you can typedef your struct to avoid having to type struct every time you use it:

typedef struct student{
...
} student_t;

void addStudent(student_t person) {
...
}
drew212
  • 506
  • 3
  • 16
0

Instead of:

void addStudent(person)
{
    return;
}

try this:

void addStudent(student person)
{
    return;
}

Since you have already declared a structure called 'student' you don't necessarily have to specify so in the function implementation as in:

void addStudent(struct student person)
{
    return;
}
afmf
  • 1
  • 2