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

    Join Date
    Jul 2013
    Posts
    109
    Rep Power
    2

    Incrementing pointer a[0]+1 won't work.


    I have a simple code:

    Code:
    char *a[]= {"Hello", "Ok", "world"};
    
    printf("%s", a[1]+1);
    The output of the print is: "k" insted of "world".

    BUT, when i print like this:
    Code:
    printf("%s", a[1]+3);
    The output is the full string "world". I thought i had to increment the pointer only by 1, and the compiler knows how much (sizeof) to add in order to get to the next element in the array??

    It's as if i have to add the exact amount of chars (=3) in order to reach the next string, as if i'm going one byte at a time ?

    Is *(p+n) the only correct form ?
  2. #2
  3. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,367
    Rep Power
    1870
    > printf("%s", a[1]+1);
    > The output of the print is: "k" insted of "world".
    As it should be.
    a[1] indexes the string "Ok", and then adding 1 to the pointer gets you to the k.

    If you want "world", there is only one choice, and that's to use a[2].

    > BUT, when i print like this:
    > printf("%s", a[1]+3);
    > The output is the full string "world".
    You ran off the end of the array, and got lucky (or unlucky, depending on your point of view.

    Consider that your string constants might be stored in memory like this.
    Hello\0Ok\0world
    If a[1] is the start of the string "Ok", then adding 3 will by happy coincidence land at the start of world.

    The fact that it does is pure dumb luck.
    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
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,091
    Rep Power
    2222
    I wrote this short test program using your array:
    Code:
    #include <stdio.h>
    
    void FunWithPointers();
    
    int main()
    {
        char *a[]= {"Hello", "Ok", "world"};
        int  i, j;
    
        // process each string in the array
        for (i=0; i<3; i++)
        {
            // display the address of the string
            printf("%s is at %p\n", a[i], a[i]);
    
            // display the address of each character in the string,
            //   including that of the null-terminator (NUL).
            for (j=0; j<= strlen(a[i]); j++)
                if (a[i][j] == '\0')
                    printf("    NUL: %p\n", &a[i][j]);
                else
                    printf("    %c: %p\n", a[i][j], &a[i][j]);
            printf("\n");
        }
    
        return 0;
    }
    Code:
    C:\otros\dcw>a
    Hello is at 00401230
        H: 00401230
        e: 00401231
        l: 00401232
        l: 00401233
        o: 00401234
        NUL: 00401235
    
    Ok is at 00401236
        O: 00401236
        k: 00401237
        NUL: 00401238
    
    world is at 00401239
        w: 00401239
        o: 0040123A
        r: 0040123B
        l: 0040123C
        d: 0040123D
        NUL: 0040123E
    
    
    C:\otros\dcw>
    For me (MinGW gcc version 2.95.3-6 (mingw special) under Win7 64-bit), those strings were indeed stored sequentially. However, there is no guarantee that your own compiler or any other C compiler would store those strings in that manner. For example, if you use a string literal more than once, most compilers will optimize by creating only one string literal and have all instances of it in the code use that one literal.

    To test that, I modify the program, moving the array down into a function and using the same literals in a printf:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    void FunWithPointers();
    
    int main()
    {
        printf("%s, %s %s!\n\n", "Ok", "Hello", "world");
        FunWithPointers();
        return 0;
    }
    
    void FunWithPointers()
    {
        char *a[]= {"Hello", "Ok", "world"};
        int  i, j;
    
        for (i=0; i<3; i++)
        {
            printf("%s is at %p\n", a[i], a[i]);
            for (j=0; j<= strlen(a[i]); j++)
                if (a[i][j] == '\0')
                    printf("    NUL: %p\n", &a[i][j]);
                else
                    printf("    %c: %p\n", a[i][j], &a[i][j]);
            printf("\n");
        }
    }
    The output I got from that was:
    Code:
    C:\otros\dcw>a
    Ok, Hello world!
    
    Hello is at 00401236
        H: 00401236
        e: 00401237
        l: 00401238
        l: 00401239
        o: 0040123A
        NUL: 0040123B
    
    Ok is at 0040123C
        O: 0040123C
        k: 0040123D
        NUL: 0040123E
    
    world is at 00401230
        w: 00401230
        o: 00401231
        r: 00401232
        l: 00401233
        d: 00401234
        NUL: 00401235
    
    
    C:\otros\dcw>
    "Completely mixed up", right? Actually not, since by convention the arguments are processed right to left, "world" was created first, then "Hello", and finally "Ok". You will see that they appear in memory in that order.

    Making na´ve assumptions about what's happening under the hood can cause you problems. And it is far better to know than to guess.

    And BTW, your na´ve assumptions failed to take the null-terminator into account. Never ever forget about the null-terminator!
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    109
    Rep Power
    2
    I think i got the idea: it's all to do with levels of indirection.

    >> Yeah, i actually got the NULL on the output a few times, not seeing why it happened.

    Thanks a lot for the help, really appreciate it :)
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    35
    Rep Power
    1
    use printf("%s",a[2]);
    to get world.
    Since you uses a[1] it takes ok\0.
    Then for a[1]+1 k\0.
    That's why you o/p like this

IMN logo majestic logo threadwatch logo seochat tools logo