0

I'm new to C and still learning about pointers. I was just testing my understanding of pointers by trying to simulate appending to an array when I got an Access Violation Read Loaction error when using printf. This is the code:

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

int arraySize(int *arrayToSize);

void changeAll(int ***a1PtrPtrPtr, int nToAdd){
    int *bPtr = (int *)malloc((arraySize(**a1PtrPtrPtr) + 1) * sizeof(int));
    int i = 0;
    while (*(**a1PtrPtrPtr + i) != -1){
        bPtr[i] = *(**a1PtrPtrPtr + i);
        i++;
    }
    bPtr[i] = nToAdd; i++;
    bPtr[i] = -1;

    *a1PtrPtrPtr = &bPtr;
}

int main(void){
    int a[4] = { 1, 2, 3, -1 };
    int *aPtr = a;
    int **aPtrPtr = &aPtr;
    int ***aPtrPtrPtr = &aPtrPtr;
    int n = 4;

    changeAll(aPtrPtrPtr, n);

    int counter = 0;
    while (counter < 5){
        int temp = *(*aPtrPtr + counter);
        printf("%d is %d", counter, temp );
        counter++;
    }

    return 0;
}

int arraySize(int *arrayToSize){
    int sizeTemp = 0;
    int i = 0;
    while (arrayToSize[i] != -1){
        sizeTemp++;
        i++;
    }
    sizeTemp++;
    return sizeTemp;
}

I get the error the second time I print in the while loop in main() when counter = 1. What I don't understand is that if I comment out that printf statement and look at the value of temp value in my IDE (MVSE 2013) it is exactly as I wanted and expected i.e. temp will be 1 then 2,3,4,-1.

What is going on please and thanks in advance for any help.

Mick
  • 89
  • 9
  • 1
    `*a1PtrPtrPtr = &bPtr` - you know `bPtr` doesn't even exist after that function returns, right? You're saving the address of an automatic variable that is long-gone after the function returns. – WhozCraig Mar 23 '15 at 04:14
  • @WhozCraig That looks good as an answer, to me. – autistic Mar 23 '15 at 04:19
  • I'm slightly confused because I thought that memory was allocated with malloc until I free it. Is that not the case? – Mick Mar 23 '15 at 04:24
  • @Mick the memory at the address *held in* `bPtr`, yes; the memory at the address *of* `bPtr` *itself*, **no**. – WhozCraig Mar 23 '15 at 04:42
  • Use `int temp = *(*aPtrPtr)++;`. Run your while loop `while (counter < 4)` – Himanshu Mar 23 '15 at 04:46

1 Answers1

1

Firstly, in case you're wondering how this appeared to sometimes work, you really should read this stellar answer to another somewhat related question.

In short, you're saving an address to an automatic variable from inside a function, then treating said-address like it is still valid after the function returns. That the automatic variable is a pointer referring to dynamic data is irrelevant. The variable itself is no longer valid once the function expires, and thus dereferencing its use-to-be-address invokes undefined behavior:

void changeAll(int ***a1PtrPtrPtr, int nToAdd)
{
    // NOTE: local variable here
    int *bPtr = (int *)malloc((arraySize(**a1PtrPtrPtr) + 1) * sizeof(int));
    int i = 0;
    while (*(**a1PtrPtrPtr + i) != -1){
        bPtr[i] = *(**a1PtrPtrPtr + i);
        i++;
    }
    bPtr[i] = nToAdd; i++;
    bPtr[i] = -1;

    // NOTE: saving address of local variable here
    *a1PtrPtrPtr = &bPtr;
}

With how this is setup, the quickest fix is simply this:

**a1PtrPtrPtr = bPtr;

instead of what you have. This will save the dynamic allocation result to the correct location (which is ultimately the address held in aPtr back in main()). It looks hideous (and frankly, it is), but it will work.

Best of luck.

Community
  • 1
  • 1
WhozCraig
  • 65,258
  • 11
  • 75
  • 141