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

Time:10-15

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.

CodePudding user response:

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.

CodePudding user response:

For argument's sake, let us assume the following:

  • sizeof(char) is 1 (by definition)
  • sizeof(char *) is 4 (e.g. on a system with 32-bit pointers)
  • char data[20][300] is stored at address 10000 (arbitrary)
  • char *wsklan[20] is stored at address 20000 (arbitrary)

Then:

  • &wsklan[0] is converted to (char **)20000
  • &wsklan[1] is converted to (char **)20004
  • &wsklan[2] is converted to (char **)20008

Note: Unary & has lower precedence than [ ], so &wsklan[0] means &(wsklan[0]).

and:

  • data[0] and &data[0][0] are converted to (char *)10000
  • data[1] and &data[1][0] are converted to (char *)10300
  • data[2] and &data[2][0] are converted to (char *)10600

Note: &data[0][0] means &((data[0])[0]).

After:

    wsklan[0] = data[0];
    wsklan[1] = data[1];

then:

  • wsklan[0] and &wsklan[0][0] are converted to (char *)10000 (same as data[0] and &data[0][0])
  • wsklan[1] and &wsklan[1][0] are converted to (char *)10300 (same as data[1] and &data[1][0])

Comparing &wsklan[0] and &wsklan[0][0] from above to summarize:

  • &wsklan[0] is converted to (char **)20000
  • &wsklan[0][0] is converted to (char *)10000 (same as &data[0][0])
  • Related