Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate over of an array of structures

In my application I use an array of structs and I need to iterate over the array. What is the proper way to do it? How can I check if I have reached the end of the array?

// structure
struct MyData {
  int count;
  char name[20];
  float average;
}

I have tried iterating like this, but my application crashes:

struct MyData data[2] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;

while (*ptr != NULL) {
  // print the contents, works ok for 2 elements

  ptr++; // increment the pointer
}
like image 575
Dariusz Avatar asked Sep 20 '13 10:09

Dariusz


Video Answer


2 Answers

How is an array of structs allocated

In your case, the MyData[2] array looks like this in memory:

| count | name | average | count | name | average |
^ -- your ptr points here 

This is a single, continuous space with size 2 * sizeof (struct MyData).

Whenever you perform a ptr++ operation the pointer will move to the next structure in the array, which means that it takes into account the size of a single struct MyData.

| count | name | average | count | name | average |
                         ^ -- after ptr++ your ptr points here

After another ptr++ your pointer will point to the memory just after your array.

| count | name | average | count | name | average | 
                                                  ^ -- another ptr++ and your ptr points here

When you dereference your ptr pointer you access memory which is not yet used or even allocated. This is undefined behavior and because of that your application crashes.

How to iterate?

There are several ways to do it. Note that not all ways are applicable in all cases.

A simple for

Very often we simply know the size of the array. We can then just use a normal for loop to iterate over the contents.

int len = 2;
struct MyData data[len] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;
for (int i=0; i<len; i++, ptr++ ) {
   // do your thing with the ptr
   // and note that ptr gets increased inside for
}

Using sizeof to determine array length

struct MyData data[2] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;
struct MyData* endPtr = data + sizeof(data)/sizeof(data[0]);
while ( ptr < endPtr ){
   // do your thing with the ptr
   ptr++;
}

The sizeof(data)/sizeof(data[0]) calculates the amount of elements: gets the total size of an array and divides it by the size of a single element.

This method has its drawbacks. It can not be used when the array is declared as a pointer! For example, when we pass the array as a parameter to a function it usually gets converted to a pointer - and then we can not determine the size of the array.

like image 66
Dariusz Avatar answered Oct 08 '22 08:10

Dariusz


If you don't have any control on the size of the array and can even not ask for it, you could try reorganize your code, not using an array of MyData but an array of pointers to MyData. Your array must then be one slot longer to store a guard with NULL value.

Your iteration will look like the one you wrote as an example.

// N is the number of MyData instances you have
MyData* vData[N+1];
// vData[i] is filled, and vData[N] = NULL

// ...

MyData* vPtr = vData[0];
while(vPtr) {
    // ...
}

But this involves changing the type of your array from MyData[] to MyData*[]. If you can't, you should follow Dariusz answer.

like image 33
Oragon Efreet Avatar answered Oct 08 '22 08:10

Oragon Efreet