Reputation: 1448
So I have the following array fib_sequence
in C passed to a function as *fib_sequence[]
.
My function segfaults when I access an element by doing:
*fib_sequence[i]
However it works when I do:
fib_sequence[0][i]
Am I going insane or are these not equivalent?
For reference here is the entire function, it failed when assigned to index 1 only.
Segfault function
void fib(int *fib_sequence[], int count) {
*fib_sequence = malloc(sizeof(int[count]));
for (int i = 0; i < count; i++) {
if (i == 0) {
*fib_sequence[i] = 0;
} else if (i == 1) {
*fib_sequence[i] = 1;
} else if (i >= 2) {
*fib_sequence[i] = *fib_sequence[i-2] + *fib_sequence[i-1];
}
}
}
Working Function
void fib(int *fib_sequence[], int count) {
*fib_sequence = malloc(sizeof(int[count]));
for (int i = 0; i < count; i++) {
if (i == 0) {
fib_sequence[0][i] = 0;
} else if (i == 1) {
fib_sequence[0][i] = 1;
} else if (i >= 2) {
fib_sequence[0][i] = fib_sequence[0][i-2] + fib_sequence[0][i-1];
}
}
}
Upvotes: 1
Views: 165
Reputation: 138051
Note that int *fib[]
is parsed as int* (fib)[]
; that is, an unbounded array of int*
. You probably meant int (*fib)[]
: a pointer to an unbounded array of integers. Once you make that change, your first example no longer compiles (as it should), but (*fib_sequence)[i]
and fib_sequence[0][i]
both work (also as they should).
However, *fib_sequence = malloc(sizeof(int[count]))
is now an error, because you can't assign an array value. That means that you would have to move malloc
outside of the function, or give up the int (*fib)[]
syntax and use int** fib
instead.
Upvotes: 0
Reputation: 126203
*pointer
and pointer[0]
are exactly the same in C. But that means that *fib_sequence[i]
is the same as fib_sequence[i][0]
, which is NOT the same as fib_sequence[0][i]
(unless i
happens to be 0). Suffix operators in C are all higher precedence than prefix operators.
Upvotes: 1
Reputation: 58578
They are not equivalent, because postfix operators have a higher precedence than unary. This means that *fib_sequence[i]
actually means *(fib_sequence[i])
. Then by the equivalence of *(E)
and (E)[0]
that you understand correctly, that expression means (fib_sequence[i])[0]
, from which we can drop the unnecessary parentheses to get fib_sequence[i][0]
.
Remember postfix versus unary/prefix: *E
, ++E
, &E
and others are all unary operators. E(...)
, E[]
, E->memb
, E.memb
are postfix.
All unary and postfix can be clumped together as one. When postfix is combined with postfix, it's clear: they go in one direction, from the root expression on the left, toward the right: E[i]->foo.memb(arg)[blah]
. The precedence is all the same and the associativity can obviously only be left to right.
When unaries are combined, same thing in the opposite direction: sizeof (T) &*++E
. The precedence is all the same, and the associativity is right-to-left. All of these are higher than the various binary operators.
If we put these two together, we hardly have to think:
sizeof (T) &*++E[i]->foo.memb(arg)[blah]
Once we scan past the unary operators to find the E
, the precedence situation is simply this:
sizeof (T) &*++ ( E[i]->foo.memb(arg)[blah] )
^---------------------------^
the postfix cruft all has higher precedence than the unary cruft.
Postfixes have the highest precedence, followed by unaries, then everything else.
Upvotes: 3
Reputation: 37227
You want to be aware that unary *
and []
has different "precedence", and your expression
*foo[1]
is actually parsed as
*(foo[1])
You need to parenthesize your "preference" so it functions correctly:
(*foo)[1]
On a side note: In some cases *p
is not equivalent to p[0]
, though it's always equivalent to *(p + 0)
(note the pointer arithmetic here).
Therefore, you may find p[0]
refuses to compile when p
is a function pointer, because it cannot participate in pointer arithmetics. For data pointers, *p
and p[0]
doesn't really make any difference, however.
Upvotes: 2