#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    2
    Rep Power
    0

    Doubt in pointer to pointer ?


    Hi

    Please guide me how to analyze the below program.
    main() {

    char **ptr = "hellow";
    printf("%s",**ptr);

    }
    for the above output = program does not work? why?

    if write printf("%s",ptr); output will be hellow.

    if write printf("%d\n",*ptr); output will be some garbage value.

    if write printf("%d\n",*ptr); program does not work? why?

    what i understood :-
    char **ptr means , it points to pointer to pointer of char type.
    char **ptr = "hellow"; --> How to analyze



    please guide me
  2. #2
  3. No Profile Picture
    I haz teh codez!
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Dec 2003
    Posts
    2,551
    Rep Power
    2337
    Compile with warnings on:

    Code:
    eh.c: In function ‘main’:
    eh.c:5: warning: initialization from incompatible pointer type
    eh.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
    eh.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
    I ♥ ManiacDan & requinix

    This is a sig, and not necessarily a comment on the OP:
    Please don't be a help vampire!
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,223
    Rep Power
    2222
    If your program does not compile cleanly, then you can have no idea what code the compiler generated. If you get warnings (when warnings are turned on and up!), then you program does not compile cleanly. Warnings means that you're doing something stupid which is confusing the compiler. A confused compiler has to make assumptions about what you want it to do, assumptions where are invariably not what you thought you wanted it to do. The result is a program that does something different than what you expect it to do. It is a waste of time trying to analyze the output of such a frakked up program.

    Think about what you want the program to do and how to tell it to do that. Compile it with warnings turned on and up! Do not even think of trying to run it until it has compiled cleanly.

    Remember: warnings are much more important than error messages.
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,223
    Rep Power
    2222
    Think about what you are trying to do. Think about what you're saying. Think about where and how the string is stored and how you're accessing it.

    Or is this another one of those assignments in which you're given really bad code and asked to analyze what it does?

    In 1993's C Users Journal there was an excellent article on working with multiple levels of indirection. Here's my suggestion in another thread in this forum (20 Mar 2013 -- http://forums.devshed.com/c-programm...am-941740.html):
    Originally Posted by dwise1_aol
    This exercise in multiple levels of indirection (ie, pointer to a pointer to a pointer ... ) had reminded me of an excellent pair of articles written many years ago in the C Users Journal. I just found a copy in my files:
    Pointer Power in C and C++, Parts 1 and 2 by Christopher Skelly, The C Users Journal, Feb and Mar 1993.

    If your college/university library has that magazine in its periodicals section, then burn a copy for yourself. If not, then I found it on-line in the ACM Digital Library:
    Part 1 -- http://dl.acm.org/citation.cfm?id=159671
    Part 2 -- http://dl.acm.org/citation.cfm?id=177856.177862
    I don't know what the requirements are for downloading the articles, but they don't look like they're free.

    PS
    Google on "Pointer Power in C and C++" "Christopher Skelly" for other options. I also found the articles re-posted at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 1) and at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 2).

    Share and enjoy!
    Also, in your program the declaration of main is wrong. You implicitly declare it as returning int, but then you do not return anything. What you need to do is to explicitly declare it as int and then at the end of the main function add return 0;. Never rely on C defaulting undeclared functions and variables as int.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    5
    Rep Power
    0
    Originally Posted by 2001goran
    Hi

    Please guide me how to analyze the below program.
    main() {

    char **ptr = "hellow";
    printf("%s",**ptr);

    }
    for the above output = program does not work? why?

    if write printf("%s",ptr); output will be hellow.

    if write printf("%d\n",*ptr); output will be some garbage value.

    if write printf("%d\n",*ptr); program does not work? why?

    what i understood :-
    char **ptr means , it points to pointer to pointer of char type.
    char **ptr = "hellow"; --> How to analyze



    please guide me
    Problem is you are putting the string in a 2D array of strings, because char **ptr is equivalent to char ptr[][], so for the first printf() you are printing from the base address/address of 1st character of the string, but in the 2nd printf() you are trying to print the unknown value of a memory address, so the correct form will be -> char *ptr="hellow"; which is valid string assignment in C.
  10. #6
  11. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,407
    Rep Power
    1871
    > because char **ptr is equivalent to char ptr[][],
    No they're not.
    http://c-faq.com/aryptr/index.html
    Some similarities for sure, but that's not the same as equivalence.

    Also, more cross-posting
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,223
    Rep Power
    2222
    Originally Posted by C-Nerd
    Problem is you are putting the string in a 2D array of strings, because char **ptr is equivalent to char ptr[][], ...
    That is not correct. While a 2-D array could be referred to as a char**, you can't really construct or pass a 2-D array in that manner. Plus, the vast majority of uses for char** that I've seen in over 20 years of C/C++ working experience have had absolutely nothing to do with any two-dimensional arrays.

    2001goran:

    The problem lies with
    char **ptr = "hellow";
    as is explained by the warning:
    eh.c:5: warning: initialization from incompatible pointer type
    Though some compilers would have worded that warning differently, citing "differing levels of indirection." The key lies in those "differing levels of indirection."

    Have you read at least Part 1 of Skelly's Pointer Power in C and C++ yet? You really need to, because he covers levels of indirection very well. After all, he developed the material in those articles while teaching C and C++ for the previous ten years.

    Here's a particularly pertinent part, though in reading it here you're missing out on a lot of information and clarification -- BTW, in this quote, p is a pointer:
    To review, the three attributes are:
    - location — where the pointer is itself stored (&p).
    - contents — what is stored in the pointer (p).
    - indirect value — what is stored AT the contents of pointer (*p).

    Key Fact #5 — The three attributes of a pointer represent three distinct address levels. These address levels can also be called levels of indirection.

    You may have noticed that although I discussed the contents of the pointer as the very first attribute, I am now showing the location as the top or first attribute. The reason why will become clear in just a moment.

    Let's think about these three attributes of every pointer. What do they reveal? First of all, they show that there are levels of addressing, at least three levels represented by the three attributes. Each attribute is at a different level in the addressing scheme.

    Start with p itself. p is a variable containing an address. I call p a level 1 expression. Level 1 means that p holds the address of something else. Look at what happens when you tack the ampersand onto p in front. Now you get the address of p, &p. &p is the address of something whose contents is also an address, that is, an address of an address. This I call a level 2 expression. Starting with the value &p, you can do the process of going to an address and finding a value twice.

    *p is also at a different level than p. To get to *p from p you go to an address. You use up one level of addressing and go "down" to the next lower level. So if p is level 1, *p is level 0. *p is just like other variables which don't hold addresses, such as the int variable i.

    To review, we have three different levels of indirection represented by the three attributes:
    - level 2 — location of p (&p)
    - level 1 — contents of p (p)
    - level 0 — indirect value of p (*p)

    It's not hard to imagine the levels connected together as steps on a ladder, and that's precisely the second essential programming concept about pointers, the Ladder of Indirection.

    The Ladder of Indirection

    The Ladder of Indirection is really a model of how expressions change level in pointer space. In the model, pointer space is a series of discrete planes, starting at ground level 0, and connected by a "ladder," or means of ascending and descending.

    Key Fact #6 — Pointer space is organized into a series of planes or levels.

    Every pointer expression can be assigned to one of these planes. The plane of a pointer expression is a measure of how much potential for indirection there is in that pointer expression.

    All pointers and pointer expressions can be seen as existing on particular planes in this model of pointer space. The ladder is visualized as connecting the planes from level 0 upwards to infinity. Each rung up is the next plane on the Ladder of Indirection. Each rung down is the next plane down.

    Moving up the ladder of indirection involves the process known as referencing, or taking the address of something. When you take the address of something you create a reference to that thing. References to objects are exactly what gets stored in pointers. Every pointer must have at least one level of indirection associated with it, or it couldn't be called a pointer. Some pointer expressions have two or more levels of indirection associated with them. By the way, don't be fooled by C++ references. References in C++ are a distinct set of types, so-called precisely because they do indeed store an address rather than a complete object. Referencing and dereferencing in C are general terms, synonymous with taking an address of something and with going to something by means of its address.

    Every time you take something's address you go up a level on the ladder. Every time you go to an address, you go down a level on the ladder. Different operators take you up and down the ladder in different ways.
    If two pointers are at different levels of indirection, then they are not compatible. That means that you cannot assign one to the other, you cannot compare them, and if a function expects a pointer at a particular level of indirection then you cannot pass it a pointer at a different level of indirection.

    Get it! Got it? Good!

    Now apply that to your question.
    Code:
    int main() 
    {
        char **ptr = "hellow";
        printf("%s",**ptr);
    
        return 0;
    }
    "hellow" is treated as a char array, hence as a pointer to char. It is a char* and hence is at the first level of indirection. You declare ptr to be a char**, which is at the second level of indirection. ptr and the string are at different levels of indirection, which means that they are incompatible, which is precisely what the warning tells you. What part of "incompatible pointer type" do you not understand?

    Now, what does the code do there? Who knows? You're doing something wrong, so the compiler doesn't really know what to do with it. It appears that your compiler went ahead and assigned the address of that string to ptr, even though ptr is supposed to contain the address of a pointer to that string. A different compiler could very well do something different. We have no way of predicting that. Like one forum member's signature says about depending on undefined behavior, it's like dancing barefoot on broken glass.

    Now there's the line,
    printf("%s",**ptr);
    which generates the warnings:
    eh.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
    eh.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
    Think about that one. With "%s", you're telling printf that you're going to give it a char*, a level-1 pointer. But ptr is a level-2 pointer, a char**. What is that called now? That's right, an "incompatible pointer type". And again you're doing something wrong that confuses the compiler, so in its confusion the compiler does whatever it was designed to do, which could be just about anything. Again, we cannot predict what code the compiler will generate in this case, nor what it will do, plus a different compiler can very well do something entirely different. You've shot yourself in the foot again.

    Now, it appears from what you describe that your compiler just takes an address in ptr, which should be a level-two pointer containing the address of a level-one pointer, and uses it instead as if it were a level-one pointer. When it uses ptr in that manner in which it shouldn't be used, then you get the reported result:
    Originally Posted by 2001goran
    if write printf("%s",ptr); output will be hellow.
    But the only reason that it superficially appears to work is because the code is broken and not working right.

    Originally Posted by 2001goran
    if write printf("%d\n",*ptr); output will be some garbage value.
    What the hell are you trying to do there? If you intended to print out the pointer value that ptr contains, then you should have used "%p". But as it is, you don't know the address of the string so you don't have anything to compare that value to in order for it to make any sense.

    Did you instead intend to write printf("%s",ptr) ? In that case, you should have gotten garbage because the code is broken and not working right.

    What appears to be happening with "%s" is that ptr, a level-two pointer, actually contains a level-one pointer value. When you use it incorrectly (ie, printf("%s",ptr) ), then it appears to work because it's using that level-one pointer value to satisfy printf's need for a level-one pointer value. But now that you try to use it correctly, that level-one pointer value is being misused as if it were a level-two pointer value. So then, you dereference ptr to go to the location of "hellow" which it thinks contains the address to the string, whereas in reality that location contains the string itself. That means that the characters in the string get misinterpreted as being a pointer value. Pointing to where? Well, take the ASCII values of the first four characters (0x68, 0x65, 0x6C, 0x6C) and that will give you the 32-bit address of 0x6C6C6568.

    The line you gave us, printf("%s",**ptr), is just too frakked up for words. You want to get the first character of the string, but instead you get the character at the address, 0x6C6C6568. But instead of a char, you promised printf a char*, so it's not at all happy about that: "format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’"


    Here's a scenario in which you could use ptr as a level-two pointer:
    Code:
    int main() 
    {
        char *p1 = "hellow";
        char **ptr = &p1;
        printf("%s",*ptr);
    
        return 0;
    }
    Read it and understand what it's doing.


    Bottom Line: Unless you are going to be using some intermediate pointer, ptr needs to be declared as a level-one pointer, a char* .
  14. #8
  15. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    5
    Rep Power
    0
    I see what you are trying to say, it was a silly mistake, it's suppose to be *ptr[], *ptr is definitely equivalent to ptr[] which will store a single string, so **ptr should be an array of strings :D :D
  16. #9
  17. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,223
    Rep Power
    2222
    Originally Posted by C-Nerd
    ... , so **ptr should be an array of strings :D :D
    Not "should", but rather "could". And most of the time is not. So it is misleading to tell someone that it's always or almost always used with two-dimensional arrays, because that excludes the other uses for a pointer to a pointer that have nothing to do with multi-D arrays. Plus it detracts from the fundamental theory of working with pointers, thus hindering the OP from learning how to think his way through such problems.
    Last edited by dwise1_aol; May 10th, 2013 at 09:19 AM.
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    5
    Rep Power
    0
    Originally Posted by dwise1_aol
    Not "should", but rather "could". And most of the time is not. So it is misleading to tell someone that it's always or almost always used with two-dimensional arrays, because that excludes the other uses for a pointer to a pointer that have nothing to do with multi-D arrays. Plus it detracts from the fundamental theory of working with pointers, thus hindering the OP from learning how to think his way through such problems.
    Man you are such a painful element, I admitted my mistake, didn't I? I didn't totally misguided him, did I? I corrected his problem. Pointer is always kinda confusing and different book tells different things, before I found Ritchie's book
  20. #11
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,223
    Rep Power
    2222
    No, you continued to make your mistake. Learn to take correction. If your ego is so frail and your skin so thin, then programming is not for you. Computers care nothing about your delicate feelings.

IMN logo majestic logo threadwatch logo seochat tools logo