0

I am attempting to access elements of an array of integer pointers using solely pointer arithmetic.

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

#define SIZE 9

int main(int argc, char** argv) {

    /* create dynamic array of integers */
    int** darr;
    darr = malloc(sizeof(int*) * SIZE);

    /* print addresses of integer pointers in darr */
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            printf("%p, ", (*(darr + i) + j));
        }
        printf("\n");
    }

    /* free dynamic array */
    free(darr);

    return 0;
}

I understand that the use of malloc is not necessary in this case as I have hard-coded the dimensions of the array into the program, and I am just practicing with such concepts. I am attempting to print out the addresses of the integer pointer in the array, but I can't get the right output. What am I doing wrong?

The output I get from the preceding code is as follows:

0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
0x0, 0x4, 0x8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 
1
  • malloc() can be necessary even with hard coded values as the stack is of limited size. Any non-trivial sized objects should be allocated dynamically. Commented Feb 12, 2021 at 22:30

3 Answers 3

3

This isn't an array of integers, it's an array of integer pointers, which is substantially different. Nested 2D arrays require two allocation passes, one for the main array, and N allocations for the inner array(s), like this:

int** darr = calloc(SIZE, sizeof(int*)); // Using calloc() for clarity

for (int i = 0; i < SIZE; ++i) {
  darr[i] = calloc(SIZE, sizeof(int)); // Allocate inner array
}

This means you need to unwind it much the same way, only in reverse:

for (int i = 0; i < SIZE; ++i) {
  free(darr[i]);
}

free(darr);

When it comes to displaying the value you should be thinking about the end value, as (*(darr + i) + j)) is just some random pointer.

What you mean is probably:

for (int i = 0; i < SIZE; i++) {
    for (int j = 0; j < SIZE; j++) {
        printf("%d, ", darr[i][j]);
    }
    printf("\n");
}

Note the simple darr[i][j] notation. The * operator isn't appropriate here, it just makes a mess of things and it's very easy to get the calculations wrong.

If you want the address of the int elements themselves you need to adjust this slightly:

printf("%p, ", &darr[i][j]);

Where here darr[i] is an int* representing the effective row in the array, and darr[i][j] is a specific value. &darr[i][j] is the address of such a value. Those pointers are just random junk on purpose on any modern operating system with things like ASLR so don't expect to divine much meaning from the particulars. The only thing that matters is each row is contiguous, but the rows themselves are not necessarily in any particular sequence in terms of addresses.

All that being said, you probably don't want to use a 2D array if you can use a 1D array instead. They are significantly easier to work with. The only hitch is access is a little more complicated, but only marginally.

// Allocation
int* darr = calloc(SIZE * SIZE, sizeof(int));

// Access
darr[i * SIZE + j]

// Releaase
free(darr);

Using a single allocation can offer a number of benefits, but primarily it means the whole structure can likely be cached easily. When you have multiple allocations there's a risk these are randomly strewn about and fetching them can be considerably slower.

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

9 Comments

Ah beat me to the punch :). Note though that OP does indeed want to print the addresses not the values of the array elements.
@JacobFaib "Access elements" could mean either the final int or the intermediate int*, it wasn't clear. You might be right.
"I am attempting to print out the addresses of the integer pointer in the array, but I can't get the right output." It's hidden in the text.
@JacobFaib Buried the lede. Good clarification.
I just recompiled the code with calloc and the loop initializer and I got unique addresses; Don't know what happened before (I might have recompiled the original code). Thank you @tadman.
|
2

The first mistake is to use the eyesore notation

(*(darr + i) + j)

Since *(x + y) is equal to x[y], we get the more sane notation

darr[i] + j

Now the problem is that while you allocated memory for all darr[i], none of these elements are initialized, and they're some random garbage. However in this "lucky" case, malloc left all elements initialized to 0, i.e. NULL. So what you essentially have is the loop that outputs (int*)NULL + j as a pointer.

7 Comments

Okay, so firstly, I am using such "eyesore notation" because it is instrumental to my question(i.e. "using only pointer arithmetic"), but thank you for the note. As far as I understand it, the function calloc also does the job of initializing the elements, but when substituting that function (and array notation ;)), I get the same output when attempting to print &arr[i][j], so what is the issue with how I have defined the array? Should I not get 9x9 unique addresses?
After calloc, arr[i] still isn't initialized to point at anything, so using [j] on it gives undefined behavior and would usually crash, but might also print boring numbers if you're unlucky. Or it may wipe your hard drive.
@MooingDuck how could the program wipe my hard drive if I'm running it in userland?
@MikeLowrey it could accidentally stumble on a 0day? Otherwise: devblogs.microsoft.com/oldnewthing/20140627-00/?p=633
@MooingDuck I'll play my luck.
|
0

In your code you have only one pointer with determined value which is darr. To allocate memory for the integers you need to allocate it for every single pointer in the allocated array of pointers. Then you can print those pointers.

int main(int argc, char** argv) {

    /* create dynamic array of integers */
    int** darr;
    darr = malloc(sizeof(*darr) * SIZE);
    for(int j = 0; j < SIZE; j++) {
        *(darr + j) = malloc(sizeof(**darr) * SIZE);
    }
    printf("darr  == %p\n", (void *)darr);

    /* print addresses of integer pointers in darr */
    for(int j = 0; j < SIZE; j++) {
        printf("darr + j (%d) == %p\n", j, (void *)*(darr + j));
    }
    printf("\n");

    /* free dynamic array */
    for(int j = 0; j < SIZE; j++) {
        free(*(darr + j));
    }
    free(darr);

    return 0;
}

If you also want to print the addresses of the integers in the allocated rows:

int main(int argc, char** argv) {

    /* create dynamic array of integers */
    int** darr;
    darr = malloc(sizeof(*darr) * SIZE);
    for(int j = 0; j < SIZE; j++) {
        *(darr + j) = malloc(sizeof(**darr) * SIZE);
    }
    printf("darr  == %p\n", (void *)darr);

    /* print addresses of integer pointers in darr */
    for(int j = 0; j < SIZE; j++) {
        printf("darr + j (%d) == %p | ", j, (void *)*(darr + j));
        for(int i = 0; i < SIZE; i++) {
            //addresses of integers in the allocated row of integers
            printf("%p ", *(darr + j) + i );
        }
    printf("\n");
    }

    /* free dynamic array */
    for(int j = 0; j < SIZE; j++) {
        free(*(darr + j));
    }
    free(darr);

    return 0;
}

https://godbolt.org/z/Wr3cKr

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.