0

I expected that using the & operator on an array of int in C would be assignable to int** as it works to assign an array of int (without the &) to an int*.The int is arbitrary here.

I saw this other question but it does not mention trying to assign & of an array of int to int** but to int*.. Assign address of address of array to pointer in C

For example..

#include <stdio.h>


int main()
{
    int** a;
    int b[5];
    b[1] = 123;
    
    //a = &b; //< results in output of warning "assignment to ‘int **’ from incompatible pointer type ‘int (*)[5]’"
    int* c = b;
    a = &c; //< this works
    printf("*a is %i\n", (*a)[1]);
    
    return 0;
}

From what I've read elsewhere &b above is a pointer to an array of int thus int(*)[].

It's not clear to me from the following either, because it would fall under the "Except" part because "it is the operand of [...] the unary & operator".

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression of type "pointer to type" that points to the initial element of the array object and is not an lvalue.

The above is from ISO/IEC 9899:1999 6.3.2.1/4: according to.. https://stackoverflow.com/a/3504570

EDIT: though people have answered "it isn't possible" I still have not seen an explanation as to why this isn't a feature of C. Is there any case where it would cause a problem to allow the above? I don't see how it would make sense even if considering for example calling free(*a) as you could also call free(c). A reminder here that I do not appreciate "you should do it this way" answers. Commandeering really poisons stackoverflow i.m.o.. Let people try to figure out what works for them. If all you have is a "moral reason why you shouldn't" you don't have a reason at all.

10
  • int** a is a pointer to a pointer to an int. When you dereference a that location does not contain a pointer Commented Jan 16, 2024 at 15:17
  • The type of &b is int (*)[5] which is quite different from int **. Commented Jan 16, 2024 at 15:33
  • "I expected that using the & operator on an array of int in C would be assignable to int** as it works to assign an array of int (without the &) to an int*." By that reasoning, you would need an array of int * so that you could assign it (without the &) to an int ** (which indeed you could). Commented Jan 16, 2024 at 15:40
  • @Ian Abbott that case is included in my question and is not what my question is about Commented Jan 16, 2024 at 16:04
  • 1
    That's a very dense way of saying that & returns the address of something. You can only return the address of something in memory because only things in memory have addresses. We call those things objects, and they include variables. So while using an array (int []) can degenerate into a pointer value (int *), you can't get the address of that pointer value anymore than you could get the address of 42. Commented Jan 16, 2024 at 16:31

2 Answers 2

2

As has been said before, arrays are not pointers, but they may decay into a pointer to their first element when used in most expressions. int* c = b; works because b decays into such a pointer.

Then you have found the part of the C standard naming the few exceptions when decay does not happen. For example when taking the address-of operator, &b. Since b does not decay here, we get an array and then we take the address of an array, which would result in the type "pointer to array" (of int), type int(*)[5] in this case. Nowhere are we dealing with a pointer to int here. There is no decay, there is no pointer to the first element.

Consequently, a = &b is invalid because they are incompatible and unrelated pointer types. Just forget about int** having anything to do with int arrays of any dimension - it doesn't - and anyone telling you otherwise is just confused. int** can be used to point at the first item in an array of int* if you happen to have one of those, but that's the only case when it can be used together with arrays.

a = &c; works because c is a separate pointer variable and a is pointing at that one. It is not pointing directly at the array.

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

Comments

2

int **a means a is a pointer to a int *.

There are no int * objects in b, only int objects. The only int * object in your program is c. Thus, the only address that could be stored in a is that of c.

&( b[0] ) yields an int *, so I believe you are trying for &( &( b[0] ) ). This would yield an int **, except you can't take the address of a value. You can only take the address of an object (e.g. a variable). So this doesn't work either.


The only option that would allow you to remove the int *c is to use an anonymous object.

int **a = &( (int*){ b } );   // Same as `int *c = b; int **a = &c;`.

The anonymous object has the same lifetime as c would have: automatic, i.e. it's "on the stack". So using this in a function and returning the value of a would a problem (just as if you had used c).

No advantage is gained by using an anonymous object, so this isn't a recommendation.


From what I've read elsewhere &b above is a pointer to an array of int thus int(*)[].

Close. It's an int(*)[5].

11 Comments

A cast actually works as well. Thus int** c = (int**)&a; works fine. I don't understand why this cast is required as the conversion is valid.
@MaartentenVelden C allows you do take a bananas* b and do int** c = (int**)b; just fine. Problems appear when you start to actually use and de-reference c.
@IanAbbott Yeah between that version and the one in the answer... I think I prefer int** a = (int*<::>)<%false[&b]%>; myself. If you're gonna obfuscate code, better do it in style :)
Re "not sure why", Undefined behaviour means anything could happen, including what you might consider "working". But the behaviour is unpredictable. It could even change within the same run!
@MaartentenVelden What ikegami just said, there is no trying in programming. Either you know what the code you are writing does, or you don't. If you don't, it's still perfectly possible to write code which seems to work fine but will break later, once the code has entered the territory of "undefined behavior". There's no black and white "always works"/"never works". Unless the code is 100% correct, then it always works.
|

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.