-1

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
Vitaliy
  • 3
  • 2
  • Q: Why `struct sensor *weather_station[]`? Why not simply pass "struct sensor weather_station[]" to your function? – paulsm4 Oct 22 '22 at 01:42
  • Because in C Language if you are passing a variable by reference, you must have these two things: + Calling the function on main(), you have to use ampersand & to pass the address. + The function that is going to receive that address, has to have the variable as a pointer *. – Vitaliy Oct 22 '22 at 01:44
  • 1
    @VitaliyKazyutaPetliakivskyi hint: ppl responding on this forum typically have a _significantly_ better grasp of C language than you do. When they make a suggestion, it often looks like a question _and_ it means you should learn more about the thing they are politely pointing you at... – Dúthomhas Oct 22 '22 at 01:58
  • `*weather_station[i].` Overweight code impresses only those who don't understand code... No one wants to read the code of `Sample_2()` to try to work out _why_ the function has access to **all** the elements of the array... Does it deal with a single weather_station? Then pass it the address of the single record it can deal with... (and use shorter names... Copy/paste is not coding, and you are writing for others who might eventually have to revise/update your code. Don't make them curse you... – Fe2O3 Oct 22 '22 at 02:10
  • @Dúthomhas I apologize if my answer were unpolite. I answered according to what I know, so I was expecting that if my answer were incorrect people will point it to me. – Vitaliy Oct 22 '22 at 02:41
  • @Fe2O3 Sorry if the format of the questions is overhelming. It is my first time writing at this forum, and since I always seen that people were complaining about the few amount of information about the code, I thought that that was the better way of making the question. – Vitaliy Oct 22 '22 at 02:44
  • @Fe2O3 `Sample_2` has to access to one of the fields of the array `weather_station[ ]` each time. That is why I pass `weather_station[i]` at the `main( )`. I need to pass all the structure because `Sample_2` has to access to many fields of the structure, including the internal structures. – Vitaliy Oct 22 '22 at 02:50
  • Your response is incorrect (according to the code). There is no interaction between each of the 4 "weather_station" structs in that function, yet the reader has to determine that by plowing through a lot of overly verbose code... Take constructive criticism... It's meant to be constructive... Otherwise, don't ask for others to comment when you experience problems. – Fe2O3 Oct 22 '22 at 03:15
  • _Ie_ especially if they are independent, an object-oriented design would be a good practice. Just take one station at a time, `void sample(struct sensor *station)`, `station->alarm.state = 0; . . .` Then, if you decide to have more stations, it's not any more work than it has to be. – Neil Oct 22 '22 at 03:50
  • `weather_station + i` or `&weather_station[i]` is a `pointer to struct sensor`; one dereferences it `weather_station[i]` is a `struct sensor`. (Or `i[weather_station]`.) – Neil Oct 22 '22 at 04:00
  • @Fe2O3 Ok. Thanks you for the advices. I will try to elaborate the questions and the answers in a better way next time. Moreover, next time I will rewrite the code to make it shorter and then publish it. – Vitaliy Oct 22 '22 at 14:30
  • @Neil Thank you. You answer corresponds to what @Eric Postpischil tells me. I failed when I defined at `Sample_2()` function `weather_station[]` as an **array** and as a **pointer**: `void Sample_2(struct sensor *weather_station[], int i)`. Because that does exactly what @Eric Postpischill says: `weather_station` is being declared to be a pointer to a pointer to a `struct sensor`. – Vitaliy Oct 22 '22 at 14:30
  • Instead of putting "solved" in the title, consider [accepting an answer](https://stackoverflow.com/help/accepted-answer). – dbush Oct 22 '22 at 14:36
  • In a function declaration, `*a` and `a[]` and `a[42]` all mean the same thing; it's up to you to decide which one conveys the intent most clearly. See [what is pointer decay](https://stackoverflow.com/q/1461432/2472827) (C++ question; not all answers will be relevant.) – Neil Oct 22 '22 at 22:11

1 Answers1

1

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 inweather_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 insideSample_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 `…`

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thank you very much. I have made the changes you commented and now it's working perfectly. I will take note about your Additional Notes and will try to express in a better way next time. – Vitaliy Oct 22 '22 at 14:31
  • I have to keep learning about how I write the questions because I have ommited some information and commited some mistakes: · I forgot to tell that `j = 0` and `k = 0` are defined outside the `main()`. · I have mistaken using the world **global** where talking about `weather_station`. That **global** wasn't referring that `weather_station` was a global variable. Because I had a nested structure, I used the world **global** to talk about the general structure which contains all the others. Very bad choice of word. – Vitaliy Oct 22 '22 at 14:33