Arrays, pointers and conversions

Started by
2 comments, last by ToohrVyk 15 years, 8 months ago
I need to write a function that accepts a pointer to an array of pointers to integers. It needs to be a pointer because the function needs to change it. The suggested prototype (this is for an assignment) is: void func(int ***pointers); but I can also write it as: void func(int* (*pointers)[]); Apparently they are not the same thing. With the first prototype, if I do this:
int **arr = malloc(sizeof(int*) * 5);
func(&arr);
It works fine. If I do this:
int *arr[5];
func(&arr);
I get this warning: 'function' : 'int ***' differs in levels of indirection from 'int *(*)[8]'. If I run the program anyway, I get an access violation. If I try the second way with the 2nd prototype, I get a warning saying the array subscripts are different, but if I run it anyway it works fine. I can get rid of the warning by directly specifying the array size in the prototype, but I don't want to do that because the function should work for an array of any size. So basically my question is, what is the reason for the difference in behavior? Thanks in advance.
Advertisement
Quote:Original post by Gage64
void func(int ***pointers);


This is a function which accepts a pointer to a pointer to a pointer to an integer (where every pointer can point to the beginning of an in-memory buffer instead of a single element).

Quote:void func(int* (*pointers)[]);


This is a function which accepts a pointer to an array (of unknown size) of pointers to integers. This is different from the above, because dereferencing the argument yields an array and not a pointer.

Quote:
int *arr[5];func(&arr);


This will not work with the first version, because &arr is a pointer to an array, not a pointer to a pointer. You would need to decay the array to a pointer first:

int *arr[5];int **ptr = arr;func(&ptr);


Quote:Original post by ToohrVyk
Quote:void func(int* (*pointers)[]);


... dereferencing the argument yields an array and not a pointer.


But if the first version yields a pointer, can't it just be treated like the beginning of an array?

Decaying the array to a pointer works fine without any warnings, but I don't really understand why it changes anything. Basically I'm trying to understand the behavior "behind the scenes" - I want to understand what causes the access violation.
Quote:Original post by Gage64
Decaying the array to a pointer works fine without any warnings, but I don't really understand why it changes anything. Basically I'm trying to understand the behavior "behind the scenes" - I want to understand what causes the access violation.


The unrelying reason is that arrays are not pointers at the implementation level either. The decay-array-to-pointer involves the equivalent of the address-of operator: you don't just reinterpret the bit layout of the array as an adress, you have to actually take the address of the array's first element.

In practice, here's some assembly:

void ptr_frob(int **ptr){  // movq    -8(%rbp), %rax  // movq    (%rax), %rax <--- this line!  // movl    $10, (%rax)  (*ptr)[0] = 10;}void arr_frob(int (*arr)[]){               // movq    -8(%rbp), %rax  // movl    $10, (%rax)                                      (*arr)[0] = 10;}


In short, what gets passed to the second function is the address of the first element of the array, and what is passed to the first function is the address of the address of the first element in the array, so that there is an additional dereference in the first case. When you call the first function with an argument that is compatible with the second function, that second dereference will cause your write to hit whatever the first element of the array (interpreted as an address) pointed at.

In short, at the implementation level, a pointer-to-array is usually just the address of the first element of that array, whereas a pointer-to-pointer is the address of the address of the first element.

This topic is closed to new replies.

Advertisement