Thread: strings Vs. Char pointers

  1. #16
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  2. #17
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by cpjust View Post
    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. #18
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    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. #19
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by IceDane View Post
    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).
    Last edited by tabstop; 02-02-2008 at 09:55 PM.

  5. #20
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    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. #21
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #22
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    sizeof does not evaluate its argument. *a is a char *, and that's all that matters.

  8. #23
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #24
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    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 **.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #25
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Quote Originally Posted by Elysia View Post
    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 **.
    Thanks for your answer above.

    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. #26
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    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. #27
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    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.

    Quote 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.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #28
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    I just proved that with my little sample.
    What about sizeof?
    Code:
    int ** a;
    sizeof(*a)
    
    int a[3][3];
    sizeof(*a);
    Do you think they are the same as well?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  14. #29
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by vart View Post
    What about sizeof?
    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
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #30
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. copying pointers
    By Tom Bombadil in forum C Programming
    Replies: 10
    Last Post: 05-22-2009, 01:26 PM
  2. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  3. Help with calloc and pointers to strings.
    By sweetarg in forum C Programming
    Replies: 1
    Last Post: 10-24-2005, 02:28 PM
  4. code condensing
    By bcianfrocca in forum C++ Programming
    Replies: 4
    Last Post: 09-07-2005, 09:22 AM
  5. String sorthing, file opening and saving.
    By j0hnb in forum C Programming
    Replies: 9
    Last Post: 01-23-2003, 01:18 AM