How to iterate over of an array of structures
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.
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.