Conversation started May 21, 2020 at 12:16.
May 21, 2020 12:16
@JohnRennie #include <stdio.h>
char (**d(void))[7];
char (*(*c())[4])[7];
char a[4][7] = {"Common", "Point", "Boost", "Better"};
char (*b[4])[7] = {a+3, a+1, a, a+2};

int main()
{


 printf("%s ", *((**d)()-1)[0]);
}

char (*(*c())[4])[7]
{
    return &b;
}

char (**d(void))[7]
{
    return c()[1] - 3;
}
for some reason this prints better in online C compler
#include <stdio.h>
char (**d(void))[7];
char (*(*c())[4])[7];
char a[4][7] = {"Common", "Point", "Boost", "Better"};
char (*b[4])[7] = {a+3, a+1, a, a+2};

int main()
{


 printf("%s ", *(d()-1)[0]);
}

char (*(*c())[4])[7]
{
    return &b;
}

char (**d(void))[7]
{
    return c()[1] - 3;
}
 
2 hours later…
May 21, 2020 14:48
@Aladdin That last code prints "Better" in VS as well:
D:\rhs\c>rat3
Better
Yeah
If u get anything please ping me
I can't find anything that explains it
If I run this:
int main()
{
  printf("a = %p\n", a);
  printf("b = %p\n", b);
  printf("c() returns %p\n", c());

  printf("%s ", *(d()-1)[0]);
}
I get:
D:\rhs\c>rat3
a = 00ED9000
b = 00ED901C
c() returns 00ED901C
So the function c() is just returning the address the array b starts at.
Which I don't understand because c() returns &b not b.
I wonder what happens if I change c() to be:
char (*(*c())[4])[7]
{
  return b;
}
Interesting. I now get a compile time warning, but c() still returns the address b starts at just like before.
May 21, 2020 15:05
188
Q: How come an array's address is equal to its value in C?

AlexandreIn the following bit of code, pointer values and pointer addresses differ as expected. But array values and addresses don't! How can this be? Output my_array = 0022FF00 &my_array = 0022FF00 pointer_to_array = 0022FF00 &pointer_to_array = 0022FEFC #include <stdio.h> int main() { char my...

Something is here which talks about it
Aaaaaaaaaaaah ...
Basically it says array behaves differently when there is &
OK, well that seems silly to me, but it explains why c() is returning the address that 'b' starts at.
so c()[1] is just b[1] i.e. using the made up addresses from earlier it would be 107.
Hmm ok
No wait ... gosh, this is hard. Let me add the value of d() to my program:
int main()
{
  printf("a = %p\n", a);
  printf("b = %p\n", b);
  printf("c() returns %p\n", c());
  printf("d() returns %p\n", d());

  printf("%s ", *(d()-1)[0]);
}
This prints:
D:\rhs\c>rat3
a = 001A9000
b = 001A901C
c() returns 001A901C
d() returns 001A9020
so d = c + 4 i.e. c + the size of one pointer
Ahhhhhhhh
May 21, 2020 15:15
I guess we should discuss this tomorrow when u are free
c() is a pointer to char[7]. c()[1] is the same as *(c+1*sizeof(char[7])) so it returns b+7. Then subtract 3 off this and you get b+4.
It looks complicated enough for me now
Yes, let's give up for today :-)
 
15 hours later…
May 22, 2020 05:51
Basically, “array” is a “pointer to the first element of array” but “&array” is a “pointer to whole array of 5 int”. Since “array” is pointer to int, addition of 1 resulted in an address with increment of 4 (assuming int size in your machine is 4 bytes).
Since “&array” is pointer to array of 5 ints, addition of 1 resulted in an address with increment of 4 x 5 = 20 = 0x14. Now you see why these two seemingly similar pointers are different at core level. This logic can be extended to multidimensional arrays as well. Suppose double twoDarray[5][4] is a 2D array. Here, “twoDarray” is a pointer to array of 4 int but “&twoDarray” is pointer to array of 5 rows arrays of 4 int”.
If this sounds cryptic, you can always have a small program to print these after adding 1. We hope that we could clarify that any array name itself is a pointer to the first element but & (i.e. address-of) for the array name is a pointer to the whole array itself.
Ah, OK, they are the same address but they are pointers to different objects of different sizes. That makes sense in a vague sort of way.
yea
hopeully the sprintf becomes easier now
May 22, 2020 06:10
@JohnRennie c() is a pointer to char[7]. c()[1] is the same as *(c+1*sizeof(char[7])) so it returns b+7. Then subtract 3 off this and you get b+4.
Can u explain ths
I'm working at the moment but I shouldn't be too long ...
 
1 hour later…
May 22, 2020 07:17
@Aladdin hi, are you there?
@JohnRennie hi
I've been doing some messing around with this. I modified c() to be:
/* c() returns a pointer to an object of size 16 i.e. c()+1 adds 16 bytes */
char (*(*c())[4])[7]
{
  char (*(*cc)[4])[7] = NULL;
  printf("cc = %p, cc+1 = %p\n", cc, cc+1);

  return &b;
}
The point is to check exactly what c() is returning. The line:
char (*(*cc)[4])[7] = NULL;
declares a pointer of the same type as c() and sets it to zero, and the line:
printf("cc = %p, cc+1 = %p\n", cc, cc+1);
adds 1 to it to see what happens. When I run this I get:
cc = 00000000, cc+1 = 00000010
ah
it adds 10
So adding 1 actually adds 16 bytes (10 hex)
May 22, 2020 07:33
The point is to see what is going to happen when we do c()[1] - 3 in the function d()
I modified d() to be:
char (**d(void))[7]
{
  printf("c()[1] = %p, c()[1]+1 = %p, c()[1]-3 = %p\n", c()[1], (c()[1]) + 1, (c()[1]) - 3);
  return c()[1] - 3;
}
When I run this I get:
D:\rhs\c>rat3
a = 008C9000
b = 008C901C
c()[1] = 008C902C, c()[1]+1 = 008C9030, c()[1]-3 = 008C9020
This is what I think is happening:
c() returns a pointer to b i.e. a pointer to an object of size 16 bytes
c()[1] is the same as *(c()+1)
May 22, 2020 07:40
c() returns the address of b, which is 008C901C so c()+1 adds 16 bytes to get 008C902C
The *(c()+1) dereferences this. c() was the address of the array, so when we dereference we get a pointer to an array element, and this has size 4 bytes because it is an address. So subtracting 3 actually subtracts 3*4 = 12 bytes.
12 in hex is c so 008C902C minus 12 bytes is 008C9020
Remember the address of b is 008C901C so 008C9020 is the address of b[1]
wait b is made of pointers to array of 7 chars
c is address of b
so c() returns &b which is address of array b
There are three different things here:
- the value in an element of b e.g., b[0], and this is a pointer to a char[7]
- the address of an element in b e.g. &b[0] and this is a pointer to a pointer so it has size 4 i.e. the size of an address
- the address of the array b. This has the size of the whole of b i.e. size 16
May 22, 2020 07:50
c() is returning the address of the array b, size 16, and when we dereference c() we get the address of an element in b, size 4.
That's why c()[1] - 3 ends up doing address of b + 1*16 - 3*4
i.e. the numerical value is b+4
and that is the address of b[1]
how subtle difference
one doubt
May 22, 2020 07:52
I would never have figured this out without adding all these printfs to see what the pointer arithmetic was actually doing :-)
if we do :b+1 it does b+1*4?
Yes. When you use the variable b in code it means address of the first element in b
And b contains pointers i.e. objects of length 4.
what about a+1
So b+1 adds 4 bytes to the address of the first element in b i.e. it gives you the addess of the second element in b
@Aladdin a is the address of the first element in the array a. Yes?
May 22, 2020 07:57
Hmm, wait, this gets complicated because it's a 2D array.
Oh, well let's try it:
printf("a = %p, a+1 = %p\n", a, a+1);
This prints:
a = 00EE9000, a+1 = 00EE9007
So it adds 7 bytes.
7 bytes because a is effectively pointer of a[0][0]
I don't know, I lost track of this ages ago :-)
Ah u explained it above.No worries
OK, we are nearly there
I think we have decoded the main things
it's just the derefrencing and getting the answer left
May 22, 2020 08:04
We've figured out that d() is returning the address of the second element in b
So we just need to figure out the line in main():
printf("%s ", *(d()-1)[0]);
Since d() returns the address of the first element in b then subtracting one actually subtracts 4 bytes to give the address of the first element in b.
So d()-1 = &(b[0]). OK so far?
d()-1=b+1*sizeof(address)-1*sizeof(address)
So *(d()-1) dereferences this to give the value of the first element in b i.e. the contents of b[0] and that is a+3.
that's better
and we can get "er" from there
making it pointer
case solved
May 22, 2020 08:11
Yes :-)
Because *(d()-1)[0] is the address of the character 'B' in "Better" and adding 4 to it gives the address of the 'e':
Better
    ^
so I have to add 4 to the expression
Hence passing this to sprintf prints "er"
technically it's "er\0"
May 22, 2020 08:14
Yes
 
Conversation ended May 22, 2020 at 8:14.