I have a problem when passing a nested structure by reference to a function. The thing is that the values of that nested structure do not change.
I have these structures defined:
struct alarm_event
{
int1 alarm_state;
int8 Hours;
int8 Minutes;
int8 Seconds;
};
struct stamp
{
int1 record;
int8 Hours;
int8 Minutes;
int8 Seconds;
};
struct sensor
{
char descriptor[2]; //output description
int16 raw_value; //raw adc value 10bit ADC 0-1023
int8 channel; //adc channel sensor wired into
int16 alarm_limit;
struct alarm_event alarm;
struct stamp alarm_record[2];
int1 previous;
};
Inside the main, I initialize the global structure, structure sensor:
void main()
{
struct sensor weather_station[4] = {{"L",0,0,200,{0,0,0,0},{{0,0,0,0},{0,0,0,0}},0},
{"T",0,0,300,{0,0,0,0},{{0,0,0,0},{0,0,0,0}},0},
{"P",0,0,400,{0,0,0,0},{{0,0,0,0},{0,0,0,0}},0},
{"H",0,0,500,{0,0,0,0},{{0,0,0,0},{0,0,0,0}},0}
};
}
And then after reading the ADC values in a loop function (for i starting from 0 until 3), I check if the ADC value read (stored in raw_value) is greater than the alarm_limit value. In case is greater, I store the time; Hours, Minutes and Seconds into weather_station[i].alarm and call the Sample_2 function to also store these values into weather_station[i].alarm_record[j]:
if(weather_station[i].raw_value >= weather_station[i].alarm_limit)
{
if(weather_station[i].alarm.alarm_state != 1)
{
weather_station[i].alarm.alarm_state = 1;
weather_station[i].alarm.Hours = Hours;
weather_station[i].alarm.Minutes = Minutes;
weather_station[i].alarm.Seconds = Seconds;
//**Upgrade
Sample_2(&weather_station[i], i);
}
The function named Sample_2 receive the address of the global structure weather_station[i] and I want that it changes the value of the paremeters record, Hours, Minutes, Seconds of weather_station[i].alarm_record[j].
void Sample_2(struct sensor *weather_station[], int i)
{
int1 updated = 0, allones = 0;
j = 0;
k = 0;
while(!updated)
{
if( *weather_station[i].alarm_record[j].record == 0 && allones == 0 )
{
*weather_station[i].alarm_record[j].record = 1;
*weather_station[i].alarm_record[j].Hours = *weather_station[i].alarm.Hours;
*weather_station[i].alarm_record[j].Minutes = *weather_station[i].alarm.Minutes;
*weather_station[i].alarm_record[j].Seconds = *weather_station[i].alarm.Seconds;
updated = 1;
}
if(k == 1)
*weather_station[i].previous = 0;
if ( *weather_station[i].alarm_record[k].record == 1 && allones == 1 && *weather_station[i].previous == 0 )
{
*weather_station[i].alarm_record[k].record = 1;
*weather_station[i].alarm_record[k].Hours = *weather_station[i].alarm.Hours;
*weather_station[i].alarm_record[k].Minutes =*weather_station[i].alarm.Minutes;
*weather_station[i].alarm_record[k].Seconds = *weather_station[i].alarm.Seconds;
updated = 1;
*weather_station[i].previous = 1;
if(k==1)
*weather_station[i].previous = 0;
}
j ;
if (j > 1)
{
allones = 1;
}
if(j > 2)
{
k ;
}
}
}
However, these values does not change. I tried to print those values after they have been modified but they do not change. For instance:
*weather_station[i].alarm_record[j].record = 1;
printf("weather_station[%u].slarm_record[%u].record = %u \n\r", i, j, *weather_station[i].alarm_record[j].record)
Since weather_station[i] in Sample_2() function is a pointer pointing to the address of weather_station[i] in main() function I think I am dereferencing the value of the structure correctly. If I try to use the another way to dereference the value of a pointer, this:
if( weather_station[i]->alarm_record[j].record == 0 && allones == 0 )
The code does not compile and says: Previous identifier must be a pointer. Which I do not understand, because weather_station[i] is a pointer.
NOTE. This code is an attemp to use the function Sample_2() to have a modular source code. I have another file where instead of using Sample_2(), I have all the code inside the main() and it works perfectly. Therefore, the problem has to be with the pointers.
Thanks you very much in advance.
CodePudding user response:
The code you show does not compile because j = 0;
and k = 0;
appear in Sample_2
without j
or k
having been defined and because weather_station[i].alarm_record[j].record
uses weather_station[i]
as a struct
when the weather_station
parameter has been declared as an array of pointers, which would make weather_station[i]
a pointer, not a struct
.
Sample_2(&weather_station[i], i);
This passes the address of weather_station[i]
to Sample_2
. Since weather_station[i]
is a struct sensor
, this argument is a pointer to a struct sensor
, a.k.a. struct sensor *
. But then, at the definition of Sample_2
, we have void Sample_2(struct sensor *weather_station[], int i)
. This says the parameter weather_station
will be an array of pointers to struct sensor
. A parameter declared as an array is automatically adjusted to be a pointer, so this results in weather_station
being declared to be a pointer to a pointer to a struct sensor
, a.k.a. struct sensor **
.
When you compile this, the compiler should warn you that you are passing an argument of incompatible type for the parameter. However, it might not do this if you have not properly declared Sample_2
before calling it. If you have not, do so.
If you pass &weather_station[i]
to Sample_2
, then the corresponding parameter in Sample_2
should be delcared as a pointer to a struct sensor
. It could be void Sample_2(struct sensor *weather_station, int i)
rather than void Sample_2(struct sensor *weather_station[], int i)
.
Inside Sample_2
, that struct sensor
would be accessed using an expression such as weather_station->alarm_record[j].record
. The ->
says to use the pointer weather_station
to access a struct sensor
and get its alarm_record
member. It is the same as (*weather_station)
.alarm_record[j].record. Using
[i]with it as in
weather_station[i].alarm_record[j].recordis wrong because the
[i]was already applied in the function call;
Sample_2(&weather_station[i], i);passes the address of
&weather_station[i], not the address of the start of
weather_station, so you do not want to apply
[i]again inside
Sample_2`.
Additional Notes
void main()
main
should be declared to return int
, at least, and preferable is declared with int main(void)
or int main(int argc, char *argv)
unless using implementation-specific features.
The function named Sample_2 receive the address of the global structure weather_station[i]…
(a) weather_station
is not global. It is declared inside main
, which makes the name have block scope, not global scope, and the object it names has automatic storage duration.
(b) Do not use bold for names from source code or other things from source code. Use the code style, which can be marked with the <code>
tag or the `
character, as in <code>…</code>
or `…`