0

I have started an introductory class to C. I cannot explain the output that I get from running the code below

./a.out 6

Output is:

Array A elements: 0 1 2 3 4 5 
Array B elements: 1 2 3 4 5 796830176

What I think the code is doing: When manup_array is executed, each value of the respective pointers will be incremented, but since it is post-fix, this takes effect only later on after the original value is returned.

True enough, when we print array A first, we get 0 1 2 3 4 5 (i.e. before incrementation). Subsequently when we print array B, the incrementation takes effect, so we get 1 2 3 [...]

What really puzzles me is why the last number is 796830176. Also, running this on various computers produces a different last number every time, suggesting that the pointer addressing is somehow responsible for this.

Could someone explain this to me?

Note: The outputs of each array are identical (1 2 3 4 5 6) if I use the pre-fix operator. This is consistent with what I think is going on -> the pointers don't change; only the values get updated.

#include <stdio.h>
#include <stdlib.h>

void manup_array(int *array[], int n); // Forward declaration.

int main(int argc, char *argv[])
{
    // The size N of 2 arrays are the same; obtain them from cmd line.
    int N = atoi(argv[1]); // Convert from str to int in C.

    int arrayA[N];  // Declare integer array.
    int *arrayB[N]; // Declare integer pointer array.

    for (int i = 0; i < N; i++)
    {
        arrayA[i] = i;
        arrayB[i] = &arrayA[i]; // Assign address of each element in A to element in B.
    }

    manup_array(arrayB, N);

    printf("Array A elements: ");
    for (int i = 0; i < N; i++)
    {
        printf("%d ", arrayA[i]);
    }

    printf("\n");

    printf("Array B elements: ");
    for (int i = 0; i < N; i++)
    {
        printf("%d ", *arrayB[i]);
    }

    printf("\n");

    return 0;
}

void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        *array[i]++;
    }
}
alk
  • 69,737
  • 10
  • 105
  • 255
Kevin Lee
  • 2,307
  • 26
  • 31
  • Did you write this or was it handed as an example you should learn from? In case of the latter, throw a tomato at your teacher and just forget about the whole thing; you wouldn't write code like this in a real application... – Lundin Feb 10 '14 at 08:44
  • The `[]`-operator binds tighter then the `*`-operator. So review your code for where both are applied to the same variable, and check whether their use really does is intended. – alk Feb 10 '14 at 09:09

3 Answers3

1

This is really obscure code. What is does:

The function takes an array of pointers as parameter. Since the parameter to the function had type int *array[], any change of the items of array will affect the caller and alter arrayB.

The interesting part of the function is *array[i]++;. The operator precedence rules in C state that [] has higher prio than postfix ++, which has higher prio than unary *.

Since array is an array of pointers, array[i] gives you a pointer. Not a the value it points at. Then ++ increments the pointer to point at the next item in the arrayA of main.

And then finally there is a * which takes the contents of what that pointer pointed at, and then does nothing with them. The * is superfluous and just there to confuse the reader.

So back in main, you have changed all the pointers of arrayB. arrayB[0] now points at arrayA[1] and so on. The last item of arrayB will point one item past the end of arrayA, so for the last item, you access the array out-of-bounds and get a garbage value.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Lesson learned is probably to _never_ mix `++` with other operators. It is an incredibly common cause for bugs in C. – Lundin Feb 10 '14 at 09:18
  • Thank you! Excellent explanation of what happened; realized that I was wrong in my way of thinking. Specifically, I was mistaken that I was actually increasing the value which the pointer was pointing at, because I didn't take into account the operator precedence. – Kevin Lee Feb 10 '14 at 12:27
  • I was also mistaken about how postfix operator works in trying to explain what I saw. This was indeed a class question. We were supposed to try to get an output such as: A: 0 1 2 3 4 5 B: 1 2 3 4 5 4732439 We were supposed to "increase each element of [array B] by 1". – Kevin Lee Feb 10 '14 at 13:04
  • @kevinze Please note that accessing an array out-of-bounds is aways a bug, because you invoke undefined behavior. You aren't guaranteed to get a garbage value - you might as well get a "segmentation fault" runtime crash, or the program could even go completely haywire. Your teacher should point this out, so that no student starts writing programs that rely on "getting garbage values". – Lundin Feb 10 '14 at 13:33
  • Thank you!! Indeed, I did get some segmentation fault errors too. – Kevin Lee Feb 10 '14 at 17:32
0

manup_array() increments the pointer, not the value as expected.

Modified manup_array().

void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        //*array[i]++;
        (*array[i])++;
    }
}

I suggest to refer Pointer Arithmetic: ++*ptr or *ptr++?

Community
  • 1
  • 1
Jeyaram
  • 9,158
  • 7
  • 41
  • 63
  • You should be ok with just `(*array[i])++;`. The issue here is that `*array[i]++` gets read as `*array[i] = *(array[i] + 1);`, due to the order of operations c uses. – Red Alert Feb 10 '14 at 08:37
  • @RedAlert Can you please elaborate. – Jeyaram Feb 10 '14 at 08:41
  • your modified `manup_array()` converts to `*array[i] = (*array[i]) = (*array[i]) + 1;` after the `++` is parsed, which is a bit redundant. – Red Alert Feb 10 '14 at 08:44
  • I'm pretty sure `*array[i] = (*array[i])++;` is undefined behavior. You have two writes to `array` in the same operation without a sequence point in between. Anyway, don't teach people to write code like that... – Lundin Feb 10 '14 at 08:47
  • @Lundin mistakenly added `array[i] = (*array[i])++;`. I feel `(*array[i])++;` will do the job. – Jeyaram Feb 10 '14 at 08:56
0
void manup_array(int *arr[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        int val = (*arr[0]); // get the value pointed to by the current value of arr
        val++;               // increment it
        *(arr[0]) = val;     // assign it back
        arr++;               // increase the pointer
    }
}

Incredibly obtuse, but it demonstrates what you mean to do and how your obscure code muddled up the operators.

To add, makes debugging way easier!

Mike McMahon
  • 7,096
  • 3
  • 30
  • 42
  • Except, if he wrote this himself, he probably didn't intend to increase the pointer. Plus you mixed up `arr++` with `arr[i]++`. Also you got a typo `[0]` where `[i]` was intended. – Lundin Feb 10 '14 at 09:15