# Thread: strings Vs. Char pointers

1. But it doesn't really matter because even if you use such syntax, it's still used as a pointer, hence it is a pointer and not an array. You can't get the size of the array, you can't see the contents of the array because it's a pointer.
That's a fallacy: in such a (corrected) function, one has a pointer to the first array in an array of arrays.

If we use sizeof as the determinant, then within the caller, we have an array of arrays, not a pointer to the first array of an array of arrays.

But it doesn't change that the array is basically a pointer. The compiler just needs to know how to calculate the offset. You could see an array as a tool for helping a programmer use a contiguous memory block with pointers.
It will still just use a pointer and calculate the offset.
I would sum that up as: an array is basically a pointer, but an array is not a pointer.

For the purposes of understanding how it all actually works, we can say that an array is basically a pointer. When it comes to interpreting the syntax with respect to the language, an array is not a pointer.

2. Originally Posted by cpjust
The same way that you would know how to find a[5] in a 1D array. You'd need to pass the size of the array to the function as well as the array. So if you pass a 2D array, I'm not sure why a pointer-to-pointer doesn't work since you could just pass 2 sizes along with the pointer?
Which is why you need to pass a 2-D array as a[][10], just so that you can pass the size along with the pointer. If all you have is a pointer (which is all you get with int **), you don't have the size of the array there.

The point I'm (failing to) make here is that int ** and int[][10] are not the same type at all, since the first is "just a" pointer, while the second is a pointer plus enough information to make actually using the thing work.

3. Hmm, I've never thought of this stuff the way you guys(cas especially) are putting it.

So, if I'm getting this right:

If you take the address of a char * variable initialized as a string literal, you'd get the address of the pointer variable, but if you'd take the address of an array, you'd just get the address of the first element, which in fact means that there is no real variable 'storing' the address, so to speak?

And if my thoughts are on the right track, does someone care to explain how the sizeof macro works on arrays, when it doesn't on pointers?

I do understand the difference between the two more thoroughly now, but I still can't think of a way how the macro can work?

4. Originally Posted by IceDane
Hmm, I've never thought of this stuff the way you guys(cas especially) are putting it.

So, if I'm getting this right:

If you take the address of a char * variable initialized as a string literal, you'd get the address of the pointer variable, but if you'd take the address of an array, you'd just get the address of the first element, which in fact means that there is no real variable 'storing' the address, so to speak?

And if my thoughts are on the right track, does someone care to explain how the sizeof macro works on arrays, when it doesn't on pointers?

I do understand the difference between the two more thoroughly now, but I still can't think of a way how the macro can work?
The first paragraph is basically right. If I declare int a[10][10], a (by itself) will generally decay to a pointer to first element, and &a must mean the address of (the start of) the array, so they'll give you the same value. I usually think of the variable a as storing the address and a[m][n] the actual data.

Sizeof is an operator that works on types; if you give it an expression, it is converted to its type first. So sizeof(int *) gives you the size of a pointer, sizeof(int[10]) gives you the size of a 10-element array of integers. Edit to add: And here's where the difference between a and &a comes in: with the declaration above, sizeof(a)==400 and sizeof(&a)==4 (at least on my machine, et cetera).

5. If you take the address of a char * variable initialized as a string literal, you'd get the address of the pointer variable, but if you'd take the address of an array, you'd just get the address of the first element, which in fact means that there is no real variable 'storing' the address, so to speak?
Yes, that is correct. I suppose to be really correct you get the address of the array itself, which happens to be the address of the first element, too: they just have different types. But your thinking is right on. With an array, there is not a variable that holds an address. You can think of it like this:
Code:
```char c = 's'; /* c holds the value 's' */
char a[] = "string"; /* a holds the values 's', 't', 'r', 'i', 'n', 'g', and 0 */
char *p = "string"; /* p holds an address */```
The variable a is not unlike the variable c: it contains the data you're interested in. Variable p is different: it contains an address that tells you where to find the data you're interested in (assuming you're interested in the string!)

The confusion comes along when you actually try to use the variable a. In almost every case it is converted into a pointer to its first element (this is often referred to as decaying to a pointer). The array itself is really an array, but when you try to use it, C sneaks behind your back and gives you a pointer instead.

And if my thoughts are on the right track, does someone care to explain how the sizeof macro works on arrays, when it doesn't on pointers?
Well, sizeof is an operator, it's not a macro. And it does "work" on both pointers and arrays. What sizeof does is tell you the size of the object (expression, actually, but that's not especially important here). So if you have an array of 10 char, that array is clearly 10 bytes long (a char being a byte). Your compiler can see your declaration so it can see just how big a particular array is. Thus when sizeof is applied to it, your compiler can easily yield the correct size, just like you can if you look at the declaration.

When it comes to pointers, sizeof can't tell you how large the memory area the pointer points to is. For one, the pointer might not be pointing anywhere: what should sizeof yield? Or it might point to 100 bytes, but only the first 5 contain a string. Should it yield 5 or 100? And so on. (Not to mention the fact that sizeof is evaluated at compile time, not runtime {except for C99's VLAs}).

But of course there is a perfectly reasonable value that sizeof can yield and that is the size of the pointer itself. C doesn't have a clue of how you're using a pointer; it's up to you to know what it points to, not the compiler. So sizeof works with pointers like it does any other type: the size of the object itself is given.

And if you think about it, this is useful: you know you need to know the size of an int if you want to create a dynamic "array" of ints with malloc(). The same goes for pointers (assume malloc() can't fail):
Code:
```char **a;
a = malloc(10 * sizeof *a);
a[0] = "string 1";
a[1] = "string 2";
/* etc */```
If you're interested in the size of an object pointed to, it's up to you to figure out what that means. Maybe use strlen(), if you're interested in a string length. Or if you're passing an array to a function, pass along the size, too (which you can calculate with sizeof, to bring this all back around again).

This is one of the more difficult parts of C to wrap one's head around and I'm afraid I'm just not too good at explaining it. But I hope I've at least not confused you more, if I haven't helped.

6. cas, is your example intended to be correct? Const-correctness aside, it seems to me that sizeof *a is not correct since at that point a does not point to anything (or points to garbage, if you prefer).

7. sizeof does not evaluate its argument. *a is a char *, and that's all that matters.

8. sizeof does not evaluate its argument. *a is a char *, and that's all that matters.
Yeah, C99 confirms that, though with the caveat that the operand is evaluated if it is a variable length array type.

9. Here you go, undeniable proof that an array is just a pointer:
Code:
```	char myarray[20] = { 'a', 'b', 'c' };
printf("&#37;c", *myarray);
char myarray2[10][10] = { { 'a', 'b', 'c' } };
printf("%c", **myarray2);```
Believe it or not, it works. That just proves my theory that an array is just holding the address. Because the [] operator dereferences the pointer and adds an offset depending on what element you try to access.
Of course, a pointer to pointer ** can't be the same as a 2D-array simply because the compiler cannot know the offset to add to the pointer when dereferencing it. Thus it catches your simple little mistake trying to pass the array as a pointer to pointer **.

10. Originally Posted by Elysia
Here you go, undeniable proof that an array is just a pointer:
Code:
```	char myarray[20] = { 'a', 'b', 'c' };
printf("%c", *myarray);
char myarray2[10][10] = { { 'a', 'b', 'c' } };
printf("%c", **myarray2);```
Believe it or not, it works. That just proves my theory that an array is just holding the address. Because the [] operator dereferences the pointer and adds an offset depending on what element you try to access.
Of course, a pointer to pointer ** can't be the same as a 2D-array simply because the compiler cannot know the offset to add to the pointer when dereferencing it. Thus it catches your simple little mistake trying to pass the array as a pointer to pointer **.

From reading the various answers, it seems to me that the reason why one can not pass a 2d-array as a ** is rather because it's not invalid as such, but merely to prevent coding mistakes. Like someone pointed out, if you'd pass the size along with it, it shouldn't be a problem as such.

But aye, your example shows that a 2D-array is indeed just a pointer that stores the address of the first 'unit' on the lowest level, but on a syntactical level, arrays and pointers to pointers are not the same. I believe this is what Laserlight was saying?

11. Actually with 2D arrays, they aren't the same as pointer-to-pointers.
Try this:
Code:
```#include <stdio.h>

int f1( int a[3][3] )
{
return a[1][1];
}

int f2( int* a[3] )
{
return a[1][1];
}

int f3( int** a )
{
return a[1][1];
}

int main()
{
int a[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };

printf( "a = %d", f1( a ) );
printf( "a = %d", f2( (int**)a ) );	/* Boom! */
printf( "a = %d", f3( (int**)a ) );	/* Boom! */

return 0;
}```
I think it's blowing up because when f2() & f3() try to dereference a they assume that the value stored in a[1] is a pointer, so they dereference the value of a[1] which isn't a valid address.

12. Problem with f2 is that it's an array of 3 pointers. You wanted a pointer to an array with 3 elements, right?
That would be int (*a)[3] or similar, wouldn't it?
And the problem with f3 is that the compiler has no knowing of how large each column is, so it can't calculate correct offset. Which is why we must use a special syntax with 2d-arrays in the first place.

Originally Posted by cpjust
I think it's blowing up because when f2() & f3() try to dereference a they assume that the value stored in a[1] is a pointer...
But it is! I just proved that with my little sample.
The compiler just doesn't know the correct offset.

13. I just proved that with my little sample.
Code:
```int ** a;
sizeof(*a)

int a[3][3];
sizeof(*a);```
Do you think they are the same as well?

14. Originally Posted by vart
Code:
```int ** a;
sizeof(*a)

int a[3][3];
sizeof(*a);```
Do you think they are the same as well?
That won't even compile.

--
Mats

15. That won't even compile.
I tested with:
Code:
```#include <iostream>

int main()
{
int ** a;
std::cout << sizeof(*a) << std::endl;

int b[3][3];
std::cout << sizeof(*b) << std::endl;
}```
It compiles as expected. If you mean to say that vart's code snippet is not compilable, then that is obvious.