'accessing pointed value with pointer without *

I am reading Head First C book and in pointers chapter(and pointer arithmetic) i couldnt understand something.

I have to write arrays like this to print its 3rd element:

main(){
int drinks[] = {4, 2, 3};
printf("3rd order: %i drinks\n", *(drinks + 2));
}

But when using pointer i need to write like this

void skip(char*);
int main() {
    char *msg_from_amy="dont call me";
    skip(msg_from_amy);
}

void skip(char *msg){
    puts(msg+6);
}

Shouldnt i need to write *(msg+6) to access 7th element? msg holds an address and msg+6 means ahead of 6 bytes from begining. so it is still an address, i need to write *(msg+6) to access stored value in that address from my perspective but it doesnt work. But why quoted one right answer, why i cant figure out.

Edit: Actually i asked wrongly my question. And edited code snippets. Here is output of:

puts(msg+6);
printf("%c\n", *(msg+6));
printf("%s\n", *(msg+6));
all me
a

I expected get "all me" output from 2nd printf like 1st one. But i think i understand the reason. its difference of puts and printf argument list. Thx for answers.

Btw why 3rd printf prints just a blank character?



Solution 1:[1]

I have to write arrays like this to print its 3rd element:

main(){
int drinks[] = {4, 2, 3};
printf("3rd order: %i drinks\n", *(drinks + 2));
}

No, you don't have to do that, and it is very non-idiomatic. Most people would use

printf("3rd order: %i drinks\n", drinks[2]);

Moving on ...

void skip(char *msg){
    puts(msg+6);
}

Shouldnt i need to write *(msg+6) to access 7th element?

Yes, *(msg+6) to access 7th element or, better, msg[6]. But you're not trying to access the 7th element. You are providing to puts the substring that starts at the 7th element. msg+6 is just fine for that.

Here is output of:

puts(msg+6);
printf("%c\n", *(msg+6));
printf("%s\n", *(msg+6));
all me
a

I expected get "all me" output from 2nd printf like 1st one

I don't see why. The %c formatting directive converts and prints one character, which is good because that's what you pass as the corresponding argument. It's not about a difference between puts and printf. Rather, it's mostly about the deep difference between msg+6 and *(msg+6).

Btw why 3rd printf prints just a blank character?

No one can say. The behavior of your third printf call is undefined because the formatting directive %s, which expects a char * argument, is not correctly type matched with the corresponding argument *(msg+6), which is a char. Anything could happen. And this underscores my previous point: there is no deep difference in this regard between puts and printf. You appear to want:

printf("%s\n", msg+6);

Solution 2:[2]

I expected get "all me" output from 2nd printf like 1st one.

The %c specifier is intended to print exactly one character. Furthermore, it's impossible to go to msg+7 from *(msg+6).

Btw why 3rd printf prints just a blank character?

Because %s expects a pointer. *(msg+6) is not a pointer.

You should compile with -Wall -Wextra. That will make the compiler warn you about a lot of stuff.

Solution 3:[3]

If you need the value that msg points to, you need to deference it using the * operator. So, if you want to get the sixth element pointed by msg, you need to advance by 6 and then deference it. The problem with printf("%s\n", *(msg+6)); is that %s expects a string, but *(msg+6) is a character. You can try to change %s with %c.

Remember that a string in c is a collection of characters ended by the null character '\0'.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 klutt
Solution 3 Nicolò Polazzi