I have been studying strings in C, and have been faced with the following problem, in the following code:
#include <stdio.h>
int main()
{
char *p = "foo";
printf("%p\t%p\t%p",&p[0],p,p[0]);
return 0;
}
And i have the following output:
00403024 00403024 00000066
Process returned 0 (0x0) execution time : 0.057 s
Press any key to continue.
Since p points to the first element of the string, shouldn't p[0] point to the same addres as p (and by consequence, &p[0])?
p[0] is not a pointer, it's a char.
Since you're asking for %p in your format string it gets force-cast to an invalid pointer with the value 0x00000066, which is just the ASCII value of f, the first character in the string.
If you turn on all the warnings your compiler offers you may see one that highlights this conversion and how it's a potential error.
p is of type char*. &p[0] is like &(*(p + 0)) which is to say you de-reference it to a char, then turn it back into a pointer with &. The end result is the same as the original.
You got it almost right. A pointer just stores the address of the pointee that it points to. So outputting p outputs the address of the string.
So what does [x] do when applied to such an address p? It does *(p+x); that is, it evaluates to the value that is stored at this address plus x. So in the case of p[0], you get the ASCII value of the char 'f', which is 66.
Taking the address of that again by prefixing with & gives you the address where it is stored. This is just the address of the original string, of course, because as you observed, the address of the string coincides with the address of its first element.
Related
What is the use of *& in the printf statement and how is the output R?
#include <stdio.h>
int main() {
char* str = "ReplyCodeChallenge";
printf("%c\n", *&*str);
return 0;
}
and the output is: R
This is just a matter of multiple referencing and dereferencing.
str is a string pointer
*str is equivalent to *(str + 0) which is the same as str[0]
&(*str) denotes the address of str[0]
*(&*str) simply dereferences that address and gives str[0] back to you
The brackets don't matter here because both & and * fall under the same precedence group and their associativity is from right to left.
Since str[0] is 'R', that's your output.
By this example, you can conclude that *& or (*&*&...) makes no significant difference. But not always, you may see that syntax used in function headers to receive an argument of pointer-type through pass-by-reference mechanism.
char* str = "ReplyCodeChallenge"; defines str to be a pointer to char and initializes it to point to the first character of "ReplyCodeChallenge". ("ReplyCodeChallenge" is a string literal, which is effectively an array. In this use, it is automatically converted to a pointer to its first element, and that pointer is used as the initial value for str.)
str is a pointer to char, which points to the 'R'.
*str is that char, because * gives the thing that a pointer (an address) points to.
&*str is the address of that char, because & gives the address (a pointer) of a thing.
*&*str is that char, again because * gives the thing that a pointer points to.
There are already enough good answers but I add also mine -- like in any expression, you first of all need to split it in parsing tree, in order to detect the order of evaluation of subexpressions.
*&*str
Here you have 3 applications of 2 unary operators, each of them is
prefix unary-operator. So they have the same precedence, so the parsing tree is like that
(*(&(*str)))
The first application *(str) will return the first character from the beginning of str, which has the same address as str itself. So, &*str will be the address of str. So your applications will reduce to
*str
which is the 1st character (integer that represents the ASCII code) from string.
* - dereferences the object referenced by the pointer
& - gets reference to the object
char *p = "ABCD; - &*p, &*&*p, &*&*&*p, &*&*&*p... - does nothing, it is still reference stored in the pointer.
*&*p, *&*&*p, *&*&*&*p, *&*&*&*p... - just dereferences the char referenced by the pointer p, in this case 'A'
https://godbolt.org/z/ijffmP
I am new to C language. Recently I have come across several problems regarding pointers. Would like to seek your help. Thank you very much~
Below is a code block:
char *a[2];
a[0] = "blah";
a[1] = "hmm";
printf("%s %d\n", a[0],a[0]);
printf("%s %d\n", a[1], a[1]);
Output of the above codes is "blah", address of a[0],"hmm" and address of a[1].
First question is: a[0] is supposed to be a pointer, which should contain an address. But here a[0] is assigned with a string, which is strange. Why this works?
Second question is: a[0] is a pointer, therefore printf("%d",a[0]) will naturally print the address of a[0]. However, printf("%s",a[0]) prints "blah", which is the string stored in the address whose address value is equal to the value stored in a[0]. Intuitively I think the correct syntax to print the string is to use printf("%s",*(a[0])) , which turns out to be execution error. So why printf("%s",a[0]) gives the desired string result?
Looking forward to your answers and really appreciate your help~
printf("%s %d\n", a[0],a[0]);
You should use %p to print pointers. %d is to print integers.
a[0] is supposed to be a pointer, which should contain an address. But here a[0] is assigned with a string, which is strange. Why this works?
Yes. a[0] is supposed to be a pointer, which should contain an address. Assigning a[0] to a string works because string constant is a pointer to it's first member. i.e. "blah" is a pointer to b
To verify:
printf("%p\n", "blah");
a[0] is a pointer, therefore printf("%d",a[0]) will naturally print the address of a[0]. However, printf("%s",a[0]) prints "blah", which is the string stored in the address whose address value is equal to the value stored in a[0].
printf("%p", a[0]) will print the value of a[0] which is an address and printf("%s", a[0]) will print a string stored linearly starting from address a[0]. This is because of format specifier used.
%p says print the value as address (pointer) wheres %s says print all the characters stored starting from a[0] till \0 character encounters.
Intuitively I think the correct syntax to print the string is to use printf("%s",*(a[0])) , which turns out to be execution error.
a[0] is a pointer, an address. We have character b from "blah" stored at that address. So the type of *(a[0]) is char wheres "%s" expects type char * (a pointer to character). So type mismatch.
To get the clear idea:
printf("%c",*(a[0]));
This will print the character stored at a[0] as we are dereferencing a[0] using * operator.
A string literal is actually an array of characters, which includes the terminating null character. And as all arrays, the string literal array can decay to a pointer to its first element.
And all string handling in C is using pointers to the first character, and then simply just increase the "index" until it finds the terminating character.
Also note that using the "%d" format for printing pointers is undefined, you should be using the "%p" format.
#include <stdio.h>
int main(void){
char *p = "Hello";
p = "Bye"; //Why is this valid C code? Why no derefencing operator?
int *z;
int x;
*z = x
z* = 2 //Works
z = 2 //Doesn't Work, Why does it work with characters?
char *str[2] = {"Hello","Good Bye"};
print("%s", str[1]); //Prints Good-Bye. WHY no derefrencing operator?
// Why is this valid C code? If I created an array with pointers
// shouldn't the element print the memory address and not the string?
return 0;
}
My Questions are outlined with the comments. In gerneal I'm having trouble understanding character arrays and pointers. Specifically why I can acess them without the derefrencing operator.
In gerneal I'm having trouble understanding character arrays and pointers.
This is very common for beginning C programmers. I had the same confusion back about 1985.
p = "Bye";
Since p is declared to be char*, p is simply a variable that contains a memory address of a char. The assignment above sets the value of p to be the address of the first char of the constant string "Bye", in other words the address of the letter "B".
z = 2
z is declared to be char*, so the only thing you can assign to it is the memory address of a char. You can't assign 2 to z, because 2 isn't the address of a char, it's a constant integer value.
print("%s", str[1]);
In this case, str is defined to be an array of two char* variables. In your print statement, you're printing the second of those, which is the address of the first character in the string "Good Bye".
When you type "Bye", you are actually creating what is called a String Literal. Its a special case, but essentially, when you do
p = "Bye";
What you are doing is assigning the address of this String literal to p(the string itself is stored by the compiler in a implementation dependant way (I think) ). Technically address to the first element of a char array, as Richard J. Ross III explains.
Since it is a special case, it does not work with other types.
By the way, you should likely get a compiler warning for lines like char *p = "Hello";. You should be required to define them as const char *p = "Hello"; since modifying them is undefined as the link explains.
As to the printing code.
print("%s", str[1]);
This doesnt need a dereferencing operation, since internally %s requires a pointer(specifically char *) to be passed, thus the dereferencing is done by printf. You can test this by passing a value when printf is expecting a pointer. You should get a runtime crash when it tries to dereference it.
p = "Bye";
Is an assignment of the address of the literal to the pointer.
The
array[n]
operator works in a similar way as a dereferrence of the pointer "array" increased by n. It is not the same, but it works that way.
Remember that "Hello", "Bye" all are char * not char.
So the line, p="Bye"; means that pointer p is pointing to a const char *i.e."Bye"
But in the next case with int *
*z=2 means that
`int` pointed by `z` is assigned a value of 2
while, z=2 means the pointer z points to the same int, pointed by 2.But, 2 is not a int pointer to point other ints.So, the compiler flags the error
You're confusing something: It does work with characters just as it works with integers et cetera.
What it doesn't work with are strings, because they are character arrays and arrays can only be stored in a variable using the address of their first element.
Later on, you've created an array of character pointers, or an array of strings. That means very simply that the first element of that array is a string, the second is also a string. When it comes to the printing part, you're using the second element of the array. So, unsurprisingly, the second string is printed.
If you look at it this way, you'll see that the syntax is consistent.
I was trying to learn strings in C when I came across this code.
#include <stdio.h>
int main(){
char s[] = "Hello world";
printf("%s" , s);
printf("%s" , &s);
return 0;
}
Both gave Hello World as output. According to my understanding, this output is Ok for First case. How is it working for the second one? Please clarify.
Taking the address of an array is the same as taking the address of it's first element. When the array's name is used, then it also decays to the address of it's first element- so the expressions s and &s yield the same result.
s returns the address of the first item in the array and &s returns the address of the array itself -- these happen to be the same.
In general, if you wish to be more explicit, the expression &s[0] can also be used to return the address of the first item.
s and &s return the same address and hence. This address is the location where "H" from "Hello world" is stored.
Because,
The name of the array decays to the address of the first element in an array &
The address of first element is same as address of the array.
Just for what it may be worth, if you want to get technical, your second version:
printf("%s" , &s);
has undefined behavior, and only works by accident. By explicitly taking the address, you're getting the address of the array (which is fine) but the result has the type "pointer to array of 12 characters", rather than the type "pointer to char", as required for printf's %s conversion. Since the types don't match, the result is undefined behavior.
In reality, however, that's purely a technicality -- the code will work just fine on every implementation of C of which I'm aware.
If you wanted to demonstrate that the difference exists, you could do so pretty easily though. For example:
char string[] = "hello world";
printf("without &: %p, %p\n", (void *)string, (void *)(string+1));
printf("with &: %p, %p\n", (void *)&string, (void *)(&string+1));
In the first case, string decays to a pointer to char, so on the first line, the second pointer will be exactly one greater than the first. On the second line, we're adding one to a pointer to an array of characters, so when we add one, it'll actually add the size of the array. Running this on my machine, I get results like this:
without &: 0038F96C, 0038F96D
with &: 0038F96C, 0038F978
char s[] is similar to char *s that is a charecter pointer that points to the first element of the array (it contains the address of the first element stored).
we can also store strings by storing the address of the first character. during the time of execution, computer start taking characters from that address one by one and make a string until it reaches a null character('\0').
in the above example 's' and '%s' represents the same value (the address of the starting character) hope you will get it.
if you use char s[10] (fixed length array) you will understand everything.
s is equivalent to &s[0] so we are passing address of s[0] not the address of pointer that is pointing to s[0] so it will print Hellow world in second case.
s is name of array not a pointer.
Consider the following code:
#include <stdio.h>
int main()
{
static int a[]={0,1,2,3,4};
int *p[]={a,a+1,a+2,a+3}; /* clear up to this extent */
printf(("%u\n%u\n%u",p,*p,*(*p))); /* how does this statement work? */
return 0;
}
Also is it necessary to get the value of addresses through %u,or we can use %d also?
Okay, you've created an array of integers and populated it with the integers from 0 to 4. Then you created a 4 element array of pointers to integers, and initialized it so its four elements point to the first four elements of a. So far, so good.
Then the printf is very strange. printf is passed a single argument, namely ("%u\n%u\n%u",p,p,(*p)). This is a comma-expression which means that the comma-separated expressions will be calculated in turn, and only the last one returned. Since the very first thing is a literal, and not an expression, I'd expect it to generate an error. However, without the extraneous parentheses, you have:
printf("%u\n%u\n%u\n",p, *p, *(*p));
This is legal. Three values are passed to printf, interpreted as unsigned integers (which actually only works on some systems, since what you are actually passing in are pointers in the first two cases, and they aren't guarateed to be the same size as unsigned ints) and printed.
Those values are p, *p and **p. p is an array, and so the value of p is the address of the array. *p is what p points to, which are the values of the array. *p is the first value, *(p+1) is the second value, etc. Now *p is the value stored in p[0] which is the address of a[0], so another address is printed. The third argument is **p which is the value stored at (*p), or a[0], which is 0
Do you have an extra pair of parens in your printf statement?
Anyway, you can think of this statement:
printf("%u\n%u\n%u",p,*p,*(*p));
like following a trail of pointers.
p is the pointer itself, printing it should print out the pointer's value which is the address of what it points to. In your case its an array of (int *)'s.
*p is a dereferencing operation. It allows access to the object that p points to. In the other answers you see notes made about *p being equivalent to p[0]. That's because p is pointing to the beginning of your structure, which is the start of the array.
**p is a dereferencing operation on the pointer object that p points to. Extending the example in the previous point, you can say that **p is equivalent to *(p[0]) which is equivalent to *(a) which is equivalent to a[0].
One tip that might help you when trying to decipher these sorts of statements is that keep in mind the precedence rules of C and insert parens between expressions in the statement to break up the statement. For the **p, inserting parens would do this: *(*p) which makes it clear that what you're doing is to follow two pointers to the final destination.
With those extra parentheses, the commas become comma operators so only the final **p is passed to printf. Since printf expects its first argument to be a pointer to a character string, and on most systems pointers
and integers have the same size, so the integer 0 is interpreted as a NULL pointer, and printf prints nothing at all. Or it crashes. That's the trouble with undefined behavior.
Your printf() arguments work like so:
p is an address (it's an array of pointers)
*p is also an address (it's equivalent to p[0], which is just a)
*(*p) is an integer (it's a[0])
My memory on C pointers is a tiny bit rusty, but let me see if I can recall.
p should be a memory location, it points to nothing else, other than p.
*p dereferences (goes to the memory location and returns the value there) p. since p itself is a pointer to pointers (*p[] can be also written as **p) when we dereference p we get the first value in the array definition, or the address of a.
**p dereferences *p. *p is the address of a. If we dereference that, we'll get the value we put in the first location of a, which is 0