1

Having this code:

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

struct Test { char c; } foo;

int main (void) {

   struct Test *ar[10];
   struct Test *(*p)[] = &ar; //what type of syntax is this *(*p)[]

   *(*p+1) = &foo; // the same  (*p)[1] = &foo
   //this only works


   p[0][1] = &foo  //the same as *(*p+1) 
   ////1error: invalid use of array with unspecified bounds

   (*(*p+1)+1) = &foo // the same as p[1][1] = &foo 
   ////2error: lvalue required as left operand of assignment

   //HOW TO make assignment of p[1][1] = &foo   and NOT p[0][1] ??

   return 0;
}

I am getting 2 weird errors from trying to assign an address from struct to array of structs. I would like both error explanation and how to make the assignment (viz. code) to p[1][1].

EDIT: the same as statements could be wrong. I just thought, they would be equally, if "normal" pointers (their type)

Herdsman
  • 799
  • 1
  • 7
  • 24
  • 1
    Ouch! Pointers to arrays of pointers — of indeterminate size. It's going to be hard to explain that. It can be done, but it ain't easy. I'm not convinced by your 'same as' comments, especially the first one. – Jonathan Leffler May 08 '20 at 20:52
  • @JonathanLeffler yeah, the first one is completely wrong, isn't it? `(*p)[0]` is the same as `*(*p)`. No `+1` in there. – Dave Costa May 08 '20 at 20:53
  • @JonathanLeffler they may be wrong, if so, just say that – Herdsman May 08 '20 at 20:54
  • But I mean, why are they wrong, all of them would be right if "normal pointer" or? – Herdsman May 08 '20 at 20:55
  • @Herdsman We may not be certain. Your code is frankly bizarre, at least to me. – Dave Costa May 08 '20 at 20:55
  • 4
    Mostly I'm saying "my brain hurts" and TGIF. The good news for you is that you're unlikely to come across anything so abstruse in the wild — people don't usually write code like that, not least because it is hard to understand and get right. I'm going to sit on the sidelines until many hours later. I'm hoping someone will spare me the effort of working out what's going wrong. – Jonathan Leffler May 08 '20 at 20:56
  • Might help - https://stackoverflow.com/questions/2469650/invalid-use-of-array-with-unspecified-bounds – Dave Costa May 08 '20 at 21:01
  • Might help - https://stackoverflow.com/questions/33375136/lvalue-required-as-left-operand-of-assignment-error-when-using-c – Dave Costa May 08 '20 at 21:01
  • I don't know what you mean by "normal pointer". What's an abnormal pointer? – Dave Costa May 08 '20 at 21:03
  • @DaveCosta i think this pointers have weird types, because if they have normal types (type is meant `&pointer`), it would probably work, i think at least – Herdsman May 08 '20 at 21:04
  • I would like someone very skilled and experience to answer if that hard, I really hanker for answers – Herdsman May 08 '20 at 21:11
  • What do you mean by "trying to assign an address from struct to array of structs" answering my question can make me able to answer yours – Saadi Toumi Fouad May 08 '20 at 21:13
  • trying to assign address of `struct Test { char c; } foo;` at the beginning of file. To the pointer of array (pointer to pointer) `struct Test *ar[10]; ` but with the third pointer `***p = &ar` – Herdsman May 08 '20 at 21:15
  • you mean as the first element in the array – Saadi Toumi Fouad May 08 '20 at 21:16

2 Answers2

3

Answering your comments line by line:

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

struct Test { char c; } foo;

int main (void) {

   struct Test *ar[10];
   struct Test *(*p)[] = &ar; //what type of syntax is this *(*p)[]

cdecl.org says struct Test *(*p)[] means declare p as pointer to array of pointer to struct Test. And by the way, the array is an array of unknown/unspecified size, since there's nothing in the square brackets.

   *(*p+1) = &foo; // the same  (*p)[1] = &foo
   //this only works

You're right, and yes, it works.

   p[0][1] = &foo;  //the same as *(*p+1) 
   ////1error: invalid use of array with unspecified bounds

(I added your missing semicolon.) You'd usually be right, but in this case a bit of pedantry means you're not. x[0] isn't equivalent to *x, but rather *(x + 0). Those are usually equivalent, but when x is a pointer to something of unknown size, you're not allowed to do pointer arithmetic on it.

   (*(*p+1)+1) = &foo; // the same as p[1][1] = &foo 
   ////2error: lvalue required as left operand of assignment

(I added your missing semicolon again.) Not quite. p[1][1] would be *(*(p+1)+1). You have your *s and parentheses the wrong way around.

   //HOW TO make assignment of p[1][1] = &foo   and NOT p[0][1] ??

You can't, without knowing how big the array that *p points to is.

   return 0;
}
  • So if I have determinated size say `struct Test *(*p)[10] = &ar`, then it would work? – Herdsman May 08 '20 at 21:25
  • `p[1][1]` gives me stack smashing. `*(*(p+1)+1) = &foo;` but my allocated space comes from statement ` struct Test *(*p)[10] = &ar;`, – Herdsman May 08 '20 at 21:34
  • 1
    @Herdsman Sorry, let me clarify. I meant "work" as in "valid to the compiler". That won't do what you want at runtime because you only have one array, but `p[1]` will try to access a nonexistent second array. – Joseph Sible-Reinstate Monica May 08 '20 at 21:36
  • So how could I allocate new array to add the second needed space to achieve the above, something like `realloc(p, sizeof(&p)*2)`? – Herdsman May 08 '20 at 21:44
  • @Herdsman `struct Test *ar[2][10]; struct Test *(*p)[10] = ar;` – Joseph Sible-Reinstate Monica May 08 '20 at 22:21
  • yes, but that is handcoded array, I meant if there is possibility to allocate new memory within an existing array, which would be in my case well suited way of that. – Herdsman May 08 '20 at 23:21
  • @Herdsman `struct Test *(*p)[10] = malloc(2 * sizeof *p);` And then you can change it later, say to 5, with `p = realloc(p, 5 * sizeof *p);` – Joseph Sible-Reinstate Monica May 08 '20 at 23:23
  • Last question: I have added space to second array pointer: `*(*p+1) = malloc(sizeof(struct Test)*2);` space for two structs. Now I would like to make `p[0][1][1] = foo` which I am trying to achieve like this: `*(*p+1)+1 = &foo;` (or: `(*(*p+1)+1) = &foo;` -- added only parethesis, but the same err), but that is the error: `lvalue required as left operand of assignment`, how make it? – Herdsman May 09 '20 at 17:01
  • @Herdsman `*(*p+1)+1` means `p[0][1] + 1`. You probably meant `*(*(*p+1)+1)`. – Joseph Sible-Reinstate Monica May 09 '20 at 17:03
  • But that is dereferenced. I want to assign address `&foo` (type struct Test*). If I do `*(*(*p+1)+1) = foo` it is only shallow copy. I cannot then assign member 'c' to the foo by the pointer `p` – Herdsman May 09 '20 at 17:06
  • I need to assign a address of `&foo` in order to manipulate with the pointer and used it to assign it a member of that struct. Is it posible to somehow assign address in order to have bind to pointer `p[0][1][1]`? – Herdsman May 09 '20 at 17:08
  • @Herdsman That doesn't work for the same reason `x + 4 = 7;` doesn't work. C isn't an equation solver. – Joseph Sible-Reinstate Monica May 09 '20 at 19:23
  • So is it possible or not? Can I assign address of `foo` to `p[0][1][1]` and manipulate with that struct? because `p` is like `struct Test ***p`, which can have 3 brackets – Herdsman May 09 '20 at 19:28
  • @Herdsman Not directly. You'd need to `malloc` at least enough room for two of them, and then store the pointer to that to `p[0][1]`. – Joseph Sible-Reinstate Monica May 09 '20 at 19:30
  • I gave new question, here https://stackoverflow.com/questions/61702828/how-to-initialize-a-struct-address-to-array-pointer – Herdsman May 09 '20 at 19:53
0

From the C Standard (6.5.2.1 Array subscripting)

Constraints

1 One of the expressions shall have type ‘‘pointer to complete object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

In the left side hand of the assignment

p[0][1] = &foo 

o is a pointer to an incomplete object type due to the declaration

struct Test *(*p)[] = &ar;

where the type Test *[] is incomplete type because the size of the array is unknown (unspecified). So the compiler issues an error.

In this statement

*(*p+1) = &foo;

the dereferenced pointer p (*p) used in the expression *p + 1 is converted to pointer to the first element of the array ar and has the type struct Test **. The expression *p + 1 points to the second element of the array and after dereferencing *( *p + 1 ) you get lvalue of the second element of the array that gets the address of the object foo.

In this statement

(*(*p+1)+1) = &foo;

there is used rvalue of the kind pointer + 1. SO you may not assign to this temporary object a value.

It looks the same as in this code snippet

int a[] = { 1, 2 };
int *p = &a[0];

p + 1 = &a[1];
halfer
  • 19,824
  • 17
  • 99
  • 186
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • So is this one wrong? `(*(*p+1)+1) = &foo;`? if so, then how should be correct? – Herdsman May 08 '20 at 21:47
  • @Herdsman It does not make sense. The expression *( *p + 1 ) yields the second element of the array. Its value was set to &foo. Now you are getting the address of the memory after the object foo and are trying to set it to &foo. – Vlad from Moscow May 08 '20 at 21:57