2

I am studying C from a book and I try various stuff in order to understand the language better. I am attempting to pass a value from a function to a global struct. I am having trouble because I perform a printf to see if the values were passed indeed but the results show different values:

#include <stdio.h>

void receive_date(); //prototype of the function


struct date_example {
    int day;
    int month;
    int year;
};

int main()
{
    struct date_example d;
    receive_date();
    //this line below shows different values than those provided by the scanf inside the function
    printf("the day is %d and the month is %d and the year is %d",d.day,d.month,d.year); 
    return 0;
}



void receive_date(void)
{
    struct date_example d;
    printf("give day: \n");
    scanf("%d", &d.day);
    printf("give month: \n");
    scanf("%d", &d.month);
    printf("give year: \n");
    scanf("%d", &d.year);
    printf("the date is: %.1d %.1d %.1d \n", d.day, d.month, d.year );
}

the result is the following:

give day:
2
give month:
3
give year:
2021
the date is: 2 3 2021
the day is 32758 and the month is 0 and the year is 0  // this is the part that gives different values
Process finished with exit code 0
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
user17850871
  • 79
  • 1
  • 6

3 Answers3

2

You do not have a global struct, i.e. not a variable which is global and of struct type. Only the type declaration is "global".

To be more explicit, you have this line twice, once in each function.

struct date_example d;

The one inside main() makes a local variable, which can only be accessed from main().
The one inside receive_date makes a local one there, which is the one accessed from all lines mentioning it within that function.

So whatever you do inside receive_date affects the local, but not the other one, which is local to main().

What ever you printf inside that function from the d local to that function is irrelevant and invisible in/from main().

If you do want whatever you do to d within the second function to have an effect which is visible from main() then you need to delete those two identical lines and make a single one outside of both functions, i.e. outside of main() and outside the other function. It will define a single global d, which is accessed from both functions.

However, "you need to" only refers to your learning experiment.
It actually is not a recommended design to use global variables.
You would better use return values, or (probably slightly more advanced than you might currently be) parameters of pointers to variables to manipulate from within a function.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
2

This only creates the struct, but does not create a struct variable:

struct date_example {
    int day;
    int month;
    int year;
};

Then, your code defines the struct variable in automatic space (local scope):

int main()
{
    struct date_example d;
    ...

}

To make it global, simply put this statement right after your struct definition:

struct date_example {
    int day;
    int month;
    int year;
};

struct date_example d;

Then modify the following to use the new global...

int main()
{
    //struct date_example d;//already defined in global space
    receive_date();
    ...
}
void receive_date(void)
{
    //struct date_example 'd', already defined in global space.
    printf("give day: \n");
    scanf("%d", &d.day);
    printf("give month: \n");
    scanf("%d", &d.month);
    printf("give year: \n");
    scanf("%d", &d.year);
    printf("the date is: %.1d %.1d %.1d \n", d.day, d.month, d.year );
}

Caveat
All of this said, using global variables is not always the best method. Although globals have their place, they should be used sparingly. Consider passing a pointer to the instance of your struct as an alternative. Here is how...

//assuming same struct definition as before...
//change prototype to accept pointer instance of struct date_example
void receive_date(struct date_example *d);

int main(void)
{
    struct date_example date = {0};//define instance of struct date_example here
    receive_date(&date);//pass address of 'date'
    printf("the date is: %.1d %.1d %.1d \n", date.day, date.month, date.year );
    return 0;//use a return statement to exit program
}

void receive_date(struct date_example *d)
{
    //using pointer argument d
    printf("give day: \n");
    scanf("%d", &d->day);//note change from . to -> for pointer notation
    printf("give month: \n");
    scanf("%d", &d->month);
    printf("give year: \n");
    scanf("%d", &d->year);
    //to illustrate, call printf in main()
    //printf("the date is: %.1d %.1d %.1d \n", d.day, d.month, d.year );
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 2
    I removed the local variable d from the main and the function, added the ``struct date_example d;`` under the struct declaration and it worked correctly. – user17850871 Feb 14 '22 at 17:08
1

Assign values to a global struct from a function

For starters you have neither global object of the structure type.

In your program you have two local objects of the structure type that have automatic storage duration. That means that they are not alive outside scopes where they are defined.

In the function receive_date

void receive_date(void)
{
    struct date_example d;
    printf("give day: \n");
    scanf("%d", &d.day);
    printf("give month: \n");
    scanf("%d", &d.month);
    printf("give year: \n");
    scanf("%d", &d.year);
    printf("the date is: %.1d %.1d %.1d \n", d.day, d.month, d.year );
}

you initialized its local variable d that is not visible and alive outside the function.

In main you are trying to output data members of the object d that were not initialized

int main()
{
    struct date_example d;
    receive_date();
    //this line below shows different values than those provided by the scanf inside the function
    printf("the day is %d and the month is %d and the year is %d",d.day,d.month,d.year); 
    return 0;
}

So the code invokes undefined behavior.

You could update the program the following way

void receive_date( struct date_example *d );

Pay attention to that in this case you need to move the structure definition before the function declaration.

The function main will look like

int main()
{
    struct date_example d;
    receive_date( &d );
    //this line below shows different values than those provided by the scanf inside the function
    printf("the day is %d and the month is %d and the year is %d",d.day,d.month,d.year); 
    return 0;
}

and the function receive_date will be defined like

void receive_date( struct date_example *d )
{
    printf("give day: \n");
    scanf("%d", &d->day);
    printf("give month: \n");
    scanf("%d", &d->month);
    printf("give year: \n");
    scanf("%d", &d->year);
    printf("the date is: %.1d %.1d %.1d \n", d->day, d->month, d->year );
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • thank you for explaining that part. How is the proper way? – user17850871 Feb 14 '22 at 16:56
  • @user17850871 See my appended post. – Vlad from Moscow Feb 14 '22 at 16:57
  • it says: Conflicting types for 'receive_date' – user17850871 Feb 14 '22 at 17:03
  • @user17850871 I am sorry. Place the structure definition before the function declaration. – Vlad from Moscow Feb 14 '22 at 17:08
  • Thanks, I upvoted all the answers as they were really helpful. Could you please tell me more about your answer? You used pointers here but it can be done without them probably. Please see the comment I left to the other answer where by adding the statement right after the struct definition made it work without pointers. I am starting to learn pointers now so it helped to see them here but clarify on your answer more on how it works. – user17850871 Feb 14 '22 at 17:15
  • @user17850871 It is not enough to add an object of the structure type after the structure definition. You also need to remove the both local objects of the structure type within the functions. In this case you declared a global object that is visible in the whole program. But in general it is a bad approach. You should declare objects in minimal scopes where they are used. – Vlad from Moscow Feb 14 '22 at 17:19