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.
Related
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.
Some example code:
#include <stdio.h>
void func0(char *x)
{
printf("func0, %s, %zu\n", x, sizeof(x));
}
//for comparison with func0
void func1(char **x)
{
printf("func1, %s, %zu\n", *x, sizeof(*x));
}
int main()
{
char x[10] = "hello";
printf("%s, %zu, %zu, %zu\n", x, sizeof(x), sizeof(*x), sizeof("hello"));
func0(x);
func1(&x);
return 0;
}
For func1() (for comparison with func0), there is a "warning: incompatible pointer types passing 'char (*)[10]' to parameter of type 'char **'" and "Segmentation fault" error.
But for func0(), isn't the type 'char [10]' converted to 'char *'? If so, how is printf("%s") still able to print out "hello"? As shown in the output of func0():
hello, 10, 1, 6
func0, hello, 8
Is the information of length (i.e. N of char[N]) passed to func0?
What is the difference between x in func0 and *x in func1? Aren't they both an address pointing to a char?
Thank you very much.
[EDIT] Thank you so much for the detailed answers!
Let me summarise the warning and error for func1().
char x[10] = "hello";
The type of &x is char (*)[10], which is a pointer to an array, not pointer to pointer (e.g. char **). Hence the warning.
x is already the address (pointing to the string), and you can only take the address of an actual memory space. &x is not the address of x. **x in func1(): trying to read from an illegal address (the value of "H" in this example?), hence the Segmentation fault.
The extra question is:
What is the use case for using &x (e.g. char (*) [N])?
I see the difference between x and &x, char * / char[N] vs. char (*) [N], but I cannot figure out a case when you have to use char( *) [N]. x and &x are the same address after all.
there is a "warning: incompatible pointer types passing char (*)[10] to parameter of type char **" and "Segmentation fault" error.
That's right, &x expression produces a pointer to array of ten characters, hence the warning. If you want to pass a pointer to pointer, make a pointer, and take a pointer of it:
char *px = x; // alternatively you could write &x[0]
func1(&px);
But for func0(), isn't the type char [10] converted to char *?
That's right, character array "decays" to character pointer when you make a function call.
how is printf("%s") still able to print out "hello"
This is possible because x contains a null-terminated sequence of characters. Therefore, printf does not need to know the size of the array when processing %s: stopping at '\0' is sufficient.
Essentially, %s does not need to know the size of the array, it needs to know the length of the string, in the same way strlen "knows" it:
printf("func0, %s, %lu\n", x, strlen(x));
// Prints hello 5
I see the difference between x (char / char[N]) and &x, but I cannot figure out a case when you have to use char(*) [N]
Here is a small example:
void print_many(char (*rows)[10], size_t count) {
for (size_t i = 0 ; i != count ; i++) {
printf("%zu: %s\n", i+1, rows[i]);
}
}
you call it like this:
char rows[10][] = {"quick", "brown", "fox"};
print_many(rows, 3);
Demo.
Is the information of length (i.e. N of char[N]) passed to func0?
No. The parameter for func0 is char *. This is a pointer to char, nothing else. There is no length associated with it.
But for func0(), isn't the type 'char [10]' converted to 'char *'?
Yes. When x, which has type char [10], is used as a function argument, it is automatically converted to a pointer to its first argument. So the function receives a pointer to char.
If so, how is printf("%s") still able to print out "hello"?
The pointer passed to printf must point to the first character of a string whose end is marked by a null character. Thus, the pointer it receives points to a char containing 'h', after which there is a char containing 'e', then 'l', then 'l', then 'o', then zero. printf prints characters one by one until it sees the zero.
What is the difference between x in func0 and *x in func1?
If func1 were passed a pointer to a pointer to char, then using *x to pass a pointer to char to printf could be okay. However, your call to func1 is func1(&x). This is not passing a pointer to a pointer to a char. Since x is an array of 10 char, &x is a pointer to an array of 10 char. It is not a pointer to a pointer.
An array is not a pointer. Although arrays are often automatically converted to pointers, this automatic conversion does not happen when the array is the operand of unary &. (It also does not happen when the array is the operand of sizeof or _Alignof, or when the array is a string literal used to initialize an array.)
To produce a pointer to a pointer to char from the array x, you would have to take the address of a pointer to its first character. There is no way to do this in a simple expression, because x is the array, not a pointer. You could create a pointer to its first character with char *y = x;, and then you could pass &y to func1.
Note
Do not print sizes from sizeof using %lu. Use %zu. The z modifier is specifically for the size type, size_t.
For the question in the title, print("%s\n", x) does not care if x is a pointer or an array, as long as it contains a zero-terminated string.
Next, only the topmost dimension of an array can be transparently coerced to a pointer, that's what the warning about.
Finally, &x points to the zero elements of your array, so when you dereference it in func1, array's first few elements (might be even eight of them, so two the rightmost are not even initialized) are reinterpreted as a pointer-to char which almost certainly points to nowhere. That's how the segfault arised.
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.
why in the below code int *p = 22 will give compile time error and ptr will print the value successfully .
int main()
{
/*taking a character pointer and assigning a string to it*/
char *ptr = "Stackoverflow" ; //correct
/*taking a int pointer and assigning a string to it*/
int *p = 22 ; //incorrect
printf("%s",ptr); // correct and print
printf("%d",p); //incorrect and give compile time error.
return 0;
}
If you have a character array as for example
char s[] = "Stackoverflow";
then the array designator used in expressions it is converted to pointer to its first element. So you may write
char *ptr = s;
The pointer ptr now points to the first character of the array s.
String literals in C are also represented like character arrays and stored in memory like character arrays with the static storage duration.
So for example the string literal "Stackoverflow" has the type char[14] (including the terminating zero).
So then you write
char *ptr = "Stackoverflow";
then this statement in fact the same if there would be
static char unnamed[] = "Stackoverflow";
char *ptr = unnamed;
As for this statement
int *p = 22 ;
then the integer literal is not converted to a pointer to itself. It represents literally the number 22 and nothing more.
So the compiler issues a message because if you want that the pointer indeed contained the integer value 22 then you have to use a casting.
The expression
22 == 22
always yields true.
While this expression
"Stackoverflow" == "Stackoverflow"
is not necessary yields true because depending on compiler options the compiler can place coincidental string literals in different memory areas. And in this expression it is the pointers to the first characters of the string literals that are compared.
Take into account that if you are going to output an integer object pointed to by a pointer you need to use dereferencing. So in any case instead of
printf("%d",p);
you should write
printf("%d", *p);
Or if you want to output the value stored in a pointer you have to use another format specifier
printf("%p", p);
Because the string is actually an array of char's and when assigning an array to a variable, the arrays will behave as a pointer to the first element of the array. This can be confusing. More on this here:
when does a array act as a pointer in c?
The integer on the other hand is just an integer, not an array of integers.
This line assigns the memory address to be 22. This is incorrect. While this line will compile with only a warning, it will crash your program at runtime when you try to access memory address 22 later in the code.
int *p = 22 ; //incorrect
This will give you the result you're looking for:
int *p = NULL;
int val = 22;
p = &val;
Also
printf("%d",p); //incorrect and give compile time error.
printf("%d",*p); //you must derefence the pointer
%s takes a pointer to char, where it is a null terminated string, while %d takes an int, not an int*.
#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.