Search code examples
cpointersc-strings

Why do addresses in array of char type pointers wsklan[0] and wsklan[0][0] differ?


Might be a silly question for you, and I couldn't find a good question for that, but the thing is - I don't understand and I'm asking you to explain that concept to me so I can understand, I would be really grateful.

So, the thing is - I was wondering, first of all, why that line of code:

printf("address of wsklan[0] %p\n", &wsklan[0])

would print different address than:

printf("address of wsklan[0][0] %p\n", &wsklan[0][0]);

I'm guessing that's because in the first case, that is an address of a pointer, and in the second one - an address of a char variable. But why exactly the address is different? I thought that the address of wsklan[0] is the address of the first char.

How is the string stored in memory? Is the string one after another in memory? So if I type 'onetwo' and second string 'threefour', it would be one after another?

And second question - why can't I use the puts function like this?:

puts(wsklan+1)

but I can use it like this?

puts(wsklan[1])

Full code snippet:

#include <stdio.h>
#include <string.h>

char *read(char *z, int amount);

int main(void){
    
    char data[20][300];
    char * wsklan[20];
    read(data[0], 300);
    read(data[1], 300);
    wsklan[0] = data[0];
    wsklan[1] = data[1];
    printf("addres wsklan[0][0] %p\n", &wsklan[0][0]);
    printf("addres wsklan[1][0] %p\n", &wsklan[1][0]);
    puts(wsklan[0]);
    puts(wsklan[1]);
    putchar(*wsklan[1]);

    return 0;
}

char *read(char *z, int amount){
    char * res;

    int i = 0;

    res = fgets(z, amount, stdin);

    if(res){
        while(z[i] != '\n' && z[i] != '\0')
            i++;
        if(z[i] != '\n')
            z[i] = '\0';
        else
            while(getchar() != '\n')
                continue;
    }

    return res;

}

Thank you for your understanding and helping me in understanding the concept in general. That code snippet is from Stephen Prata's C book, I modified it slightly.


Solution

  • Assuming the declaration is char * wsklan[20];.

    In the expression &wsklan[0], [] takes precedence over &, so we get pointer number 0. Then & gives the address of that pointer. Since it's the first item in the array, you can assume it's the same address as obtained by &wsklan.

    In the expression &wsklan[0][0] we also get pointer number 0, then again [] takes precedence over & so we get character number 0 in the array that pointer number 0 points at. Then & gives the address of that single character. What address that is depends on where you set the pointer to point at. It makes perfect sense that it points at a different address than where the pointer itself is stored. (Since a pointer pointing at its own address would be quite useless.)

    Second question: wsklan[1] is 100% equivalent to *(wsklan + 1). So it has a different meaning than just wsklan + 1. Since the variable is of type "array of character pointers", it "decays" into a pointer to the first item when used in an expression. That would be a pointer to character pointer, char**. That's not what printf expects - you'll have to de-reference it into a plain char* first.