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' );