1

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];
        }
    }
}
4
  • Small note: In some cases *p is not equivalent to p[0], though it's always equivalent to *(p + 0) (note the pointer arithmetic here). Commented Jan 23, 2019 at 2:10
  • Try (*fibSequence)[0]. Commented Jan 23, 2019 at 2:13
  • @iBug: "In some cases *p is not equivalent to p[0]" in which cases, please? Commented Jan 23, 2019 at 12:24
  • @alk see the end of my answer below Commented Jan 23, 2019 at 12:36

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

2 Comments

You're correct however someone answered before you so I marked them as correct.
@Ge0rges Yep I know. That's actually a meme on this site :)
1

*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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.