Home > Software design >  Iterating though an array of structs in C
Iterating though an array of structs in C

Time:10-05

Can someone explain this for loop to me?

struct {
  int lock;   // not used in Lab
  struct proc proc[NPROC];
} ptable;

void scheduler(void){
struct proc *p;

  acquire(&ptable.lock);
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p  ){
    if(p == curr_proc || p->state != RUNNABLE)
      continue;

    // Switch to chosen process.
    curr_proc = p;
    p->state = RUNNING;
    break;
  }
  release(&ptable.lock);

}

Mostly I'm asking about the for loop

  for(p = ptable.proc; p < &ptable.proc[NPROC]; p  ){

What does assigning the pointer p to ptable.proc do? And how do I access the struct proc's members/variables?

CodePudding user response:

Mostly I'm asking about the for loop

for(p = ptable.proc; p < &ptable.proc[NPROC]; p  ){
p = ptable.proc

Here the array ptable.proc decays into a pointer to the first element in the array and p is assigned this pointer. It's the same as doing p = &ptable.proc[0].

p < &ptable.proc[NPROC]

Here p is compared with the address one element outside the array bounds (out of bounds). ptable.proc[NPROC - 1] is the last element within bounds.

p  

This steps the pointer to point at the next struct proc in the struct proc array.

So, the for-loop as a whole starts by making p point at the first struct proc in the array and iterates through all the elements in the array until p points outside the array, then it terminates the loop.

Here's an alternative loop with the same result to visualize what's going on:

// for(p = ptable.proc; p < &ptable.proc[NPROC]; p  ){
for(int idx = 0; idx < NPROC; idx  ) {
    p = &ptable.proc[idx];   // or:   p = ptable.proc   idx;

    // the rest of the loop body goes here ...
}

And how do I access the struct proc's members/variables?

You dereference the pointer p with the -> operator to access the members of the element p is pointing at. p->state accesses the state member in the struct proc that p is currently pointing at.

CodePudding user response:

p = ptable.proc assigns a pointer to the start of the array to p.

The array contains NPROC elements so &ptable.proc[NPROC] is the (notional) address of one past the last element (ptable.proc[NPROC-1] is the last element). ptable.proc NPROC would be cleaner.

p increments the pointer by the size of one struct proc.

The net effect is a pointer starts at the beginning of the array a progress up through it moving sizeof(struct proc) bytes each time visiting each element of the array until it passes the end and immediately stops.

It may look complicated but in C it is the most efficient and natural way to iterate through an array.

CodePudding user response:

If you have an array as for example like

enum { N = 10 };
int a[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

then you can access its elements using the subscript operator like for example

for ( int i = 0; i < N; i   )
{
    printf( "%d ", a[i] );
}
putchar( '\n' );

The subscript operator is evaluated like

a[i] ==> *( a   i )

But if you have a pointer to the i-th element of the array like

int *p = &a[i];

then instead of the expression a[i] you can just use the expression *p to get the value of the i-th element of the array.

Initially you can initialize the pointer p by the address of the first element of the array

int *p = &a[0];

that is equivalent to

int *p = a;

because in this case the array is implicitly converted to pointer to its first element.

So the expression *p yields the first element a[0] of the array. To output the second element of the array you could write for example p[1] that is equivalent to *( p 1 ).

But the expression p 1 yields the same value as the expression p because the expression p is evaluated like p = p 1.

So you can write to output the first element of the array

printf( "%d ", *p );

To output the second element of the array you could write

printf( "%d ", *  p );

or

  p;
printf( "%d ", *p );

and so on.

Thus the above for loop can be rewritten using a pointer the following way

for ( int *p = a; p < a   N;   p )
{
    printf( "%d ", *p );
}
putchar( '\n' );
  • Related