Pointers, dereferencing and referencing - c

I declare a pointer like this:
char *ptr = "hello";
and when I do this
printf("%p\n", *&*&ptr);
the result is address of that pointer, but when I do this
printf("%s\n", *&*&ptr);
the result is hello.
Can someone explain why?

*&*&ptr is a weird way of writing ptr (since * cancels out &).
%p expects a pointer, and prints the value of the pointer (i.e. the address to which it points). The value of ptr is therefore a valid input, and you are seeing the expected result.
%s expects a pointer to a NUL-terminated sequence of char values, and prints those char values (but not the NUL). The value of ptr is therefore a valid input, and you are seeing the expected result.

Related

Why does char* of an array point to the entire array instead of the address?

I've seen some similar questions asked on here, but haven't been able to find a concise answer.
In learning pointers, I've come to understand that
in a case of
int test=1; int* p = &test;
printing "p" with printf("%p", p); will give the address of test, while printing *p with printf("%d", *p); will give the actual value of test, which is what ptr p points to.
Now, for doing this with a char, doing
char word[] = "test"; char* ptr = &word[0];
then printing ptr with printf("%s", ptr); gives the output "test", but I expected it to give the address of word[0].
I have figured out that if I do printf("%p", ptr); it does print the address.
So my question is, does this pointer contain both the address and the value of the array test[]? Or does printf just grab what it needs based off of which of %s or %p you use, and in that case, why couldn't you just do printf("%d",test); in my earlier example and get the value of test rather than the address? Is the fact that I'm using %s automatically outputting the entire array since it starts at that address?
%s tells printf to take the pointer it is given and print the first character that is there, then the character after that, then the character after that, and so on until printf finds a null character (a character that has value zero).
So, this not about a pointer pointing to the “entire array.” The pointer just points to one thing. It is about the command given to printf. %p says “print the value of the pointer.” %s says “print the characters at the location pointed to.”
… why couldn't you just do printf("%d",test); in my earlier example and get the value of test rather than the address?
%d is a command to printf to print the value of the int it is passed. You should not pass it a pointer for this because printf is expecting an int. That is just what the command is for.

Pointers and Characters Variables in C

I'm trying to store the memory location of the evil variable in the ptr variable, but instead of the memory location, the variable prints out the value within the variable and not it's location. Both the ptr variable and the &evil syntax print the same result which is the value of the variable and not it's location in memory. Could someone please nudge me in the right direction, and help me determine the syntax needed to store the memory location of a string/char variable in C?
int main()
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
printf(ptr);//prints 4 C's
printf(&evil);//prints 4 C's
return 0;
}
That's normal, because the first parameter to printf is a format specifier, which is basically a char* pointing to a string. Your string will be printed as-is because it does not contain any format specifiers.
If you want to display a pointer's value as an address, use %p as a format specifier, and your pointer as subsequent parameter:
printf("%p", ptr);
However, note that your code invokes Undefined Behavior (UB) because your string is not null-terminated. Chances are it was null-terminated "out-of-luck".
Also notice that to be "correct code", cast the pointer to void* when sending it to printf, because different types of pointers may differ on certain platforms, and the C standard requires the parameter to be pointer-to-void. See this thread for more details: printf("%p") and casting to (void *)
printf("%p", (void*)ptr); // <-- C standard requires this cast, although it migh work without it on most compilers and platforms.
You need #include <stdio.h> for printf, and #include <string.h> for memset.
int main()
You can get away with this, but int main(void) is better.
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
This would be more legible if you replaced 0x43 by 'C'. They both mean the same thing (assuming an ASCII-based character set). Even better, don't repeat the size:
memset(evil, 'C', sizeof evil);
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
This sets ptr to the address of the initial (0th) element of the array object evil. This is not the same as the address of the array object itself. They're both the same location in memory, but &evil[0] and &evil are of different types.
You could also write this as:
ptr = evil;
You can't assign arrays, but an array expression is, in most contexts, implicitly converted to a pointer to the array's initial element.
The relationship between arrays and pointers in C can be confusing.
Rule 1: Arrays are not pointers.
Rule 2: Read section 6 of the comp.lang.c FAQ.
printf(ptr);//prints 4 C's
The first argument to printf should (almost) always be a string literal, the format string. If you give it the name of a char array variable, and it happens to contain % characters, Bad Things Can Happen. If you're just printing a string, you can use "%s" as the format string:
printf("%s\n", ptr);
(Note that I've added a newline so the output is displayed properly.)
Except that ptr doesn't point to a string. A string, by definition, is terminated by a null ('\0') character. Your evil array isn't. (It's possible that there just happens to be a null byte just after the array in memory. Do not depend on that.)
You can use a field width to determine how many characters to print:
printf("%.4s\n", ptr);
Or, to avoid the error-prone practice of having to write the same number multiple times:
printf("%.*s\n", (int)sizeof evil, evil);
Find a good document for printf if you want to understand that.
(Or, depending on what you're doing, maybe you should arrange for evil to be null-terminated in the first place.)
printf(&evil);//prints 4 C's
Ah, now we have some serious undefined behavior. The first argument to printf is a pointer to a format string; it's of type const char*. &evil is of type char (*)[4], a pointer to an array of 4 char elements. Your compiler should have warned you about that (the format string has a known type; the following arguments do not, so getting their types correct is up to you). If it seems to work, it's because &evil points to the same memory location as &evil[0], and different pointer types probably have the same representation on your systems, and perhaps there happens to be a stray '\0' just after the array -- perhaps preceded by some non-printable characters that you're not seeing.
If you want to print the address of your array object, use the %p format. It requires an argument of the pointer type void*, so you'll need to cast it:
printf("%p\n", (void*)&evil);
return 0;
}
Putting this all together and adding some bells and whistles:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ptr;
char evil[4];
memset(evil, 'C', sizeof evil);
ptr = &evil[0];
printf("ptr points to the character sequence \"%.*s\"\n",
(int)sizeof evil, evil);
printf("The address of evil[0] is %p\n", (void*)ptr);
printf("The address of evil is also %p\n", (void*)&evil);
return 0;
}
The output on my system is:
ptr points to the character sequence "CCCC"
The address of evil[0] is 0x7ffc060dc650
The address of evil is also 0x7ffc060dc650
Using
printf(ptr);//prints 4 C's
causes undefined behavior since the first argument to printf needs to be a null terminated string. In your case it is not.
Could someone please nudge me in the right direction
To print an address, you need to use the %p format specifier in the call to printf.
printf("%p\n", ptr);
or
printf("%p\n", &evil);
or
printf("%p\n", &evil[0]);
See printf documentation for all the ways it can be used.
if you want to see the address of a char - without all the array / pointer / decay oddness
int main()
{
char *ptr;
char evil;
evil = 4;
ptr = &evil;
printf("%p\n",(void*)ptr);
printf("%p\n",(void*)&evil);
return 0;
}

Multiple Reference and Dereference in C

Can somebody clealry explain me the concept behind multiple reference and dereference ? why does the following program gives output as 'h' ?
int main()
{
char *ptr = "hello";
printf("%c\n", *&*&*ptr);
getchar();
return 0;
}
and not this , instead it produces 'd' ?
int main()
{
char *ptr = "hello";
printf("%c\n", *&*&ptr);
getchar();
return 0;
}
I read that consecutive use of '*' and '&' cancels each other but this explanation does not provide the reason behind two different outputs generated in above codes?
The first program produces h because &s and *s "cancel" each other: "dereferencing an address of X" gives back the X:
ptr - a pointer to the initial character of "hello" literal
*ptr - dereference of a pointer to the initial character, i.e. the initial character
&*ptr the address of the dereference of a pointer to the initial character, i.e. a pointer to the initial character, i.e. ptr itself
And so on. As you can see, a pair *& brings you back to where you have started, so you can eliminate all such pairs from your dereference / take address expressions. Therefore, your first program's printf is equivalent to
printf("%c\n", *ptr);
The second program has undefined behavior, because a pointer is being passed to printf with the format specifier of %c. If you pass the same expression to %s, the word hello would be printed:
printf("%s\n", *&*&ptr);
Lets go through the important parts of the program:
char *ptr = "hello";
makes a pointer to char which points to the string literal "hello". Now, for the confusing part:
printf("%c\n", *&*&*ptr);
Here, %c expects a char. Let us look into what type *&*&*ptr is. ptr is a char*. Applying the dereference operator(*) gives a char. Applying the address-of operator to this char gives back the char*. This is repeated again, and finally, the * at the end gives us a char, the first character of the string literal "hello", which gets printed.
In the second program, in *&*&ptr, you first apply the & operator, which gives a char**. Applying * on this gives back the char*. This is repeated again and finally , we get a char*. But %c expects a char, not a char*. So, the second program exhibits Undefined Behavior as per the C11 standard (emphasis mine):
7.21.6.1 The fprintf function
[...]
If a conversion specification is invalid, the behavior is undefined.282 If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
So, basically, anything can happen when you execute the second program. Your program might crash, emit a segmentation-fault, output weird things, or do something else.
BTW, you are right about saying:
I read that consecutive use of '*' and '&' cancels each other
Let's break down what *&*&*ptr actually is, but first, remember that when applying * to a pointer, it gives you what that pointer points to. On the other hand, when applying & to a variable, it gives you the address in memory for that variable.
Now, after getting a steady ground, let's see what you have here:
ptr is a pointer to a char, thus when doing *ptr it gives you the data which ptr points to, in this case, ptr points to a string "hello", however, a char can hold only one char, not a whole string, right? so, it point to the beginning of such a string, which is the first character in it, aka h.
Moving on...*&*&*ptr=*&*&(*ptr) = *&*&('h')= *&*(&'h') = *&*(ptr)=*&(*ptr) = *&('h')= *ptr = 'h'
If you apply the same pattern on the next function, I'm pretty sure you can figure it out.
SUMMARY: read pointers from the right to the left!

char pointer and printf

Hi please advise me on the following output:
main()
{
char ***x = "jjhljlhjlhjl";
char **q = *x;
printf("x:%s\n",x);
printf("q:%s\n",&q);
}
Output:
x:jjhljlhjlhjl
q:jjhl
Why is q doesn't print the whole of x ?
Your program invokes undefined behavior, so there are not really any limitations on what it may output.
char ***x = "jjhljlhjlhjl";
Although x is a pointer to a pointer to a pointer, it is assigned the address of a string literal.
char **q = *x;
q is a pointer to a pointer, and is assigned the result of dereferencing x. Since x is actually pointing to an object of incompatible type, the result of derferencing it is undefined.
If we pretend like this is supposed to work, then *x is now a pointer to a pointer, and so it might treat the sizeof(char **) bytes of the string literal as if it were an address and assign that value to q.
printf("x:%s\n",x);
Since x is a pointer, that pointer value is passed to printf(). Since the %s is provided, the pointer value is treated like a string. Since x was assigned the address of a string literal, that string is what gets printed.
printf("q:%s\n",&q);
The address of q is passed to printf(). Since the %s is provided, the pointer value is treated like a string. However, derferencing the contents of that pointer is actually sizeof(char **) bytes of the string literal. There is no guarantee that the bytes read will be properly NUL terminated, so it is just happenstance that something got printed at all.
The issue is the string "jjhljlhjlhjl" is only a char *, whereas you assign it to a char ***. When you print x, it gets interpreted as a char * by printf, which winds up being the correct string.
As for printing &q as a string address, you're effectively printing the contents of q. When you dereference x, you get a char **, which in your case, is 4 bytes. But because x actually points to text data, *x will grab the first four bytes (i.e. characters) of your string. The fact that it's printing only four characters is pure chance.

Query in C Pointers

I'm trying to print a pointer of char type in c , i'm able to see the values and it's memory address as below
char *ptr = "I am a string";
printf("\n value [%s]\n",ptr);
printf("\n address [%d]\n",&ptr);
But when i print directly the pointer as below, it's showing error as Segmentation fault
char *ptr = "I am a string";
printf("\n value [%s]\n",*ptr);
Please tell me what's going wrong here
Note: if i change the format in printf to [%d] or [%i] it's printing.
*ptr is a char, not a char pointer, and %s expects a char pointer (to a C-string). When treating the char as a pointer, printf tries to access an invalid memory address, and you get a segmentation fault.
The %s format specifier expects a pointer to a 0-terminated char array. If the corresponding argument to printf is *ptr, a char, that is a) undefined behaviour and b) probably leads to the value of the character (promoted to an int) and possibly some arbitrary adjacent bytes, being interpreted as a pointer. Following that presumed pointer is likely to access memory not allocated to your program.
When you pass in the format "%s" into printf, the function expects a pointer to an array of chars.

Resources