Thread: casting - pointer to pointer

  1. #46
    Registered User
    Join Date
    Apr 2008
    Posts
    31

    Question

    [QUOTE=swoopy;744337]
    Code:
    >int compare (const void *p1, const void *p2)
    >{
    >  const char *i;
    >  const char *j;
    >
    >  i = *((char **)p1); //IF p1 & p2 are strings... what am I doing here?
    >  j = *((char **)p2);
    [code]
    Can't I just write:

    i = (char *) p1;
    j = (char *) p2;

    Huh? since *(char **) == char *

  2. #47
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    > Can't I just write:

    > i = (char *) p1;
    > j = (char *) p2;

    In a perfect world. Except, I have to assume that you are trying to sort a set of strings, in which case, that would be a misrepresentation of the data you are sorting.

    The qsort function does not actually pass any type specifics around while it sorts. Meaning that the best qsort can do is pass some two parts of your array around for comparison based on the metrics of element size and array length you gave it; after all, since it has no idea what you are sorting, it can't pass you any type information.

    So since you are sorting an array of strings, you have to represent the type yourself to make an accurate comparison:

    Code:
    int
    elem_compare ( const void * n, const void * m )
    {
       const char *const * elem1 = n;   /** I am really a pointer to a string **/
       const char *const * elem2 = m    /** I am really a pointer to a string **/
       return strcmp( *elem1, *elem2 ); /** compare ... **/
    }
    After you make a comparison, qsort moves some data around, and if it's not sorted yet, asks you to compare again, rinse and repeat. In the end, you get a sorted result according to the order your function established.

  3. #48
    Registered User
    Join Date
    Apr 2008
    Posts
    31

    Question

    [QUOTE=terminator;744339]
    Quote Originally Posted by swoopy View Post
    Code:
    >int compare (const void *p1, const void *p2)
    >{
    >  const char *i;
    >  const char *j;
    >
    >  i = *((char **)p1); //IF p1 & p2 are strings... what am I doing here?
    >  j = *((char **)p2);
    [code]
    Can't I just write:

    i = (char *) p1;
    j = (char *) p2;

    Huh? since *(char **) == char *

    [code]

    Is (char **) casting equivalent to char **ptr declaration?

  4. #49
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Is (char **) casting equivalent to char **ptr declaration?
    In some way - it is declaration and initilaization of temp object of this type

    Code:
    i = *((char **)p1);
    is translated into
    Code:
    char** temp = p1;
    i = *temp;
    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

  5. #50
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    > Is (char **) casting equivalent to char **ptr declaration?

    More or less. What vart said is a manner of understanding what casting will mean. If you feel the need to cast in C, it might mean that you should use a variable to represent the type instead. Sometimes this is overkill: casting from signed types to unsigned types should be fine, for example. By no means is there an excuse to rely on casting (see this thread) all the time, but you might encounter code that uses a cast, so you need to understand it.

  6. #51
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Quote Originally Posted by terminator View Post
    Can't I just write:
    Code:
       i = (char *) p1;
       j = (char *) p2;
    Huh? since *(char **) == char *
    Not quite, since the compare function is going to be passed offsets into this array:
    Code:
      char *words[ ] = { "Then",   "he",   "shouted", "What", "I",
                        "didn't", "hear", "what",    "you",  "said" };
    Reading from right to left, words is an array of pointers to char (char *words[]), and since arrays in C are passed as a pointer to the first element, that becomes char **words. So to get to a word in the array, you would need to dereference i and j.

    Now if there were a way to pass compare() the addresses of array elements, then indeed what you propose would work. But in this case, somewhere in qsort the call to compare() becomes:
    Code:
    compare (words+offset1, words+offset2)

  7. #52
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Quote Originally Posted by matsp View Post
    or even:
    [code]
    Code:
    int compare (const void *p1, const void *p2)
    {
      const char **ptr1 = p1;
      const char **ptr2 = p2;
      const char *i = *ptr1;
      const char *j = *ptr2;
    --
    Mats
    True. I almost added that as a second example, but was afraid it might be confusing.

  8. #53
    Registered User
    Join Date
    Apr 2008
    Posts
    31
    Quote Originally Posted by swoopy View Post
    Not quite, since the compare function is going to be passed offsets into this array:
    Code:
      char *words[ ] = { "Then",   "he",   "shouted", "What", "I",
                        "didn't", "hear", "what",    "you",  "said" };
    Reading from right to left, words is an array of pointers to char (char *words[]), and since arrays in C are passed as a pointer to the first element, that becomes char **words. So to get to a word in the array, you would need to dereference i and j.

    Now if there were a way to pass compare() the addresses of array elements, then indeed what you propose would work. But in this case, somewhere in qsort the call to compare() becomes:
    Code:
    compare (words+offset1, words+offset2)
    But the code compiles and gives the correct answer, even if I only use (char *) instead of (char **). Why's that?

  9. #54
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by terminator View Post
    But the code compiles and gives the correct answer, even if I only use (char *) instead of (char **). Why's that?
    I doubt that it compiles without warnings. It may well be that because of the way that the compiler generates the code, it HAPPENS to do the right thing anyways. It's called "undefined behaviour" - it may not work under another circumstance, and certainly isn't correct.

    --
    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.

  10. #55
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    I know VC++ will frequently fix very questionable code into what is most likely correct. But even at that, you are at the whim of what the compiler sees as "most likely correct." And even when it is kind enough to do this for you it does generate warnings about what you did, as well as what it decided was "most likely correct." Typically on a forum that revolves around technical assistance, I would suggest listening to the one's who seem to have the most technical assistance who are in agreement with one another.

    I request anyone who doesn't understand what me, matsp, and many others have described to draw a simple picture. Draw squares representing blocks of data and arrows representing pointers. After you do this, I believe this will make more sense.

  11. #56
    Registered User char's Avatar
    Join Date
    Apr 2002
    Posts
    31
    I think the reason why the OP is confused is that he/she is not aware that the calling function is actually passing pointers to pointers to char. That means that void * is interpreted by the called function as pointer to pointer to char. so the void type in this case means pointer_to_char.

    I know this explanation is little precise, but it will hopefully make things clear. I hope so.

  12. #57
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by char View Post
    I think the reason why the OP is confused is that he/she is not aware that the calling function is actually passing pointers to pointers to char. That means that void * is interpreted by the called function as pointer to pointer to char. so the void type in this case means pointer_to_char.
    If you like to think of it like that, then sure.
    But then again, void isn't a type.
    Void* is a type, but void certainly isn't, which is why you can't dereference a void 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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. casting contents of pointer?
    By nutsNguts in forum C Programming
    Replies: 8
    Last Post: 11-10-2008, 11:07 AM
  2. Ban pointers or references on classes?
    By Elysia in forum C++ Programming
    Replies: 89
    Last Post: 10-30-2007, 03:20 AM
  3. scope of a pointer?
    By Syneris in forum C++ Programming
    Replies: 6
    Last Post: 12-29-2005, 09:40 PM
  4. Question About Pointer To Pointer
    By BlitzPackage in forum C++ Programming
    Replies: 2
    Last Post: 09-19-2005, 10:19 PM
  5. pointers
    By InvariantLoop in forum C Programming
    Replies: 13
    Last Post: 02-04-2005, 09:32 AM