The output of this snippet of code:
char* str1 = "suchString";
printf("%s %s\n", &"suchString", &str1);
is:
suchString �WO:+(or any unknown symbols)
What is the difference and why the output not the same?
EDIT
If you trying to eliminate the & operator as follows:
char* str1 = "suchString";
printf("%s %s\n", "suchString", &str1);
The output is the same of the first snippet of code.
Now, is how the "suchString" is the same of &"suchString"?
This:
&"suchString"
takes the address of a string literal. String literals are arrays, not pointers.
Had you compiled with warnings enabled, you had knew already:
prog.c:5:14: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char (*)[11]' [-Wformat=]
printf("%s %s\n", &"suchString", &str1);
~^ ~~~~~~~~~~~~~
prog.c:5:17: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'char **' [-Wformat=]
printf("%s %s\n", &"suchString", &str1);
~^ ~~~~~
The first is of type char (*)[11], while the second is of type char **.
As for the garbage values, you are providing an address of a pointer to %s format, thus ruining the print. If you used %p instead, you would see an address being printed out, e.g. "0x7ffe676f5588".
Same goes for when attempting to print the address of the string literal, with the string specifier in printf().
Moreover, you should cast to void*, like this:
printf("%p %p\n", (void*)"suchString", (void*)str1);
char* str1 = "suchString";
printf("%s %s\n", &"suchString", &str1);
The %s specifier requires an argument of type char*, which must be a pointer to a string. You've provided arguments of types char (*)[11] and char**. Your code has undefined behavior, which means that in principle it could do literally anything.
A string literal is an array. The address of an array refers to the same memory location as the address of the array's first element, but it's of a different type. Passing just "suchString" as the second argument would be correct, since the array "decays" to a pointer to its first element.
In an implementation where all pointers have the same representation (which is typical but not required), passing a pointer to the same memory location but with the wrong type is likely to "work". printf is special in that it can accept arguments of different types, so the compiler can't necessarily diagnose type errors. For a non-variadic function, an error like this would probably be rejected at compile time.
str1 is a pointer, not an array. You've initialized it to point to the initial character of the string literal. You could pass str1 to printf, but &str1 is the address of a pointer object, which is not only of the wrong type, but doesn't point to a string at all. Thus the output is garbage.
If you want to print the string values, you can do this:
const char* str1 = "suchString";
printf("%s %s\n", "suchString", str1);
(I've added const so the compiler will complain if you try to modify the contents of the string literal.)
Related
I am currently doing pointers. I have been programming for a long time, but not in C/C++. With that being said, my pointer knowledge is abysmal.
Currently, I am following a guide on YouTube and he prints the code below.
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", p);
}
This prints successfully for him, and he sees a memory location. For me, I see the error
warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'
From this, I expect I need to put an & in front of the p to make it print the value. But then I receive this error,
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", &p);
}
'int', but argument 2 has type 'int **'
Where is the hole in my knowledge? Any key tips or strategies when working with this, I don't know why I find this so abstract.
Thanks,
I was expecting the value to print as expected, but instead am greeted with the error.
%d is the wrong format specifier for pointers. That may work on a more lenient or noncompliant implementation, but you should use %p to print pointer values.
Warnings are not errors. You're receiving a warning, which is not stopping your program from working, because the print specifier %d (ie printf("%d")) is for displaying integers, and you're giving it a non-integer argument of type int*.
The problem here is not with the argument, it's with the print specifier. Your attempt at a fix just changes the int* to an int**, which still does not match the format specifier %d. Use %p instead, which is the specifier for pointers, and will fix the warning, and print the address in hexadecimal notation.
You could also suppress the warning with a series of explicit casts from int* to int, but integer representations of memory addresses are generally much less used than hexadecimal representations in the first place.
Note that using wrong format specifier in printf() lead to undefined behaviour1).
The correct format specifier to print a pointer is %p format specifier.
Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *. The correct statement to print pointer p would be:
printf("%p\n", (void *)p);
C11#7.21.6.1p9 [emphasis added]
9 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.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char str1[20];
printf("Name: ");
scanf("%s",&str1);
printf("Your name is %s",str1);
return 0;
}
it outputs fine but the the build messages say
warning: format '%s' expects argument of type char ', but argument 2 has type 'char () [20]' [-Wformat=]
str1 has type "array of 20 char" (char[20]). & makes a pointer to the operand. So &str1 has the type "pointer to array of 20 char" (char(*)[20]).
But %s expects the argument to be "pointer to char" (char*) and will store the input characters to consecutive char in memory starting with the location that the argument points to. So &str1 is not the correct type.
Since str1 is an array of char, str1[0] does have just type char and is the first element of the array, where you want scanf to begin storing to and so &str1[0] would for example have type char* and point to the correct char.
Instead you can also just write str1 instead of &str1[0], because arrays will generally (but not when & is applied directly to them) decay to pointers to the first element automatically.
It works exactly the same for printf's %s, where you are using just str1 correctly.
If I have below string in C:
char s[]="Question";
Then I noted that both of the below prtintf prints the string correctly in terminal.
1.
printf("%s\n",s);
2.
printf("%s\n",&s);
Which is a correct way to print the string in C. If both of them are same, then what is the convention followed ? 1 or 2 ?
Thanks.
char s[]="Question";
printf("%s\n",&s);
is undefined behavior because,
§7.21.6.1/8 The conversion specifiers and their meanings are:
[...]
s If no l
length modifier is present, the argument shall be a pointer to the
initial element of an array of character type.
§7.21.6.1/9 [...] If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
s in this context will decay to a pointer type. Since & yields a pointer, the type you're passing to printf is actually a pointer to a pointer.
The first one is correct, for the second one you should get a warning from your compiler, since it's UB, something like:
[Warning] format '%s' expects argument of type 'char *'
Beginner question. I have the following code:
char input[10];
scanf("%s", &input);
My compiler throws the following warning:
warning: format '%s' expects type 'char *', but argument 2 has type 'char (*)[10]'
warning: format '%s' expects type 'char *', but argument 2 has type 'char (*)[10]'
Changing to:
char * input;
Does not seem to help. What am I doing wrong?
Because an array already can be used as a pointer, so you don't need to the address-of operator.
If you read the warning message again, you will see that when you use the address-of operator on the array, you get a pointer to the array.
Try,
char input[10];
scanf("%s", input);
You don't have to give the address-of operator (&) with the name of the array input.
%s format string accepts argument of type char* where as &intput is of type char (*)[10] that is the reason you are getting warning.
format '%s' expects type 'char *', but argument 2 has type 'char (*)[10]
Note argument 2 is &input in scanf()
scanf("%s", &input);
^ ^
| argument-2
argument-1
To correct this code you should write scanf like:
scanf("%s", input);
Side note:: value wise both &input and input are same if you string address but semantically both are diffrent.
&input is address of array that is char(*) [10] type whereas input type is char[10]
To understand difference between &input and input read this two answers:
What does sizeof(&arr) returns? , and
Issue with pointer to character array C++
Edit:
Changing to: char *input will not help you instead it becomes undefined behavoiur unless and until you allocated memory to input
char input[10] is a character array.
input itself represents the base address of the array, i.e a char *.
You do not need to use the address of operator (&)with it. instead, use:
char input[10];
scanf("%s", input);
If you use char * input;, you need to allocate space for it using malloc. But in this case also, no need to use the address of operator.
scanf("%s", input);
you will get the answer.
char input[10];
scanf("%s", &input);
scanf requires the address to store the data that will be recieved. Array names already act like pointers, So you don't need the & operator to obtain the address.
format '%s' expects type 'char *', but argument 2 has type 'char (*)[10]'
When you do &input it indicates a pointer that is pointing to a char array of 10 char. char (*)[10]
input is itself char* and is only necessary to be passed as 2nd argument to scanf.
Go through this too for arrays and pointers.
I'm currently trying to wrap my head around pointers in C, coming from front-end developing this not an entirely easy endeavour. I'm following this tutorial, and everything is running smoothly until I try to compile the following example:
#include <stdio.h>
int main(int argc, char *argv[]) {
int **ramon;
int *paul;
int melissa = 5;
paul = &melissa;
ramon = &paul;
printf("ramon = %d\n", ramon); // <- warning: format '%d' expects type 'int'...
printf("&paul = %d\n", &paul); // <- warning: format '%d' expects type 'int'...
printf("*ramon = %d\n", *ramon); // <- warning: format '%d' expects type 'int'...
printf("&melissa = %d\n", &melissa); <- warning: format '%d' expects type 'int'...
printf("**ramon = %d\n", **ramon);p1); <- warning: format '%d' expects type 'int'...
return(0);
}
From the first printf line I get this error: "warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
I reckon this has to do with the way I initialize my pointers, but standing at the bottom of a steep learning curve I don't know how to progress. What is wrong, how do I initialize pointers to avoid the warnings?
Your pointer initialization looks correct. The problem is that you are trying to print a variable of type int** (i.e. a "pointer to a pointer to an int") using the %d format specifier which is for int values.
Print int value
If you want to print the value of melissa (i.e. 5) which is essentially what ramon is indirectly pointing to, you need to de-reference the pointer value the correct number of times.
De-referencing pointers is done via the * operator, and it essentially means "the value at which this pointer is pointing to".
De-referencing it once (i.e. *ramon) will get the int* value which ramon is pointing to.
De-referencing it a second time will get the int value which the de-referenced int* value is pointing to.
You can chain together de-reference operators like so to get what you want:
printf("ramon = %d\n", **ramon);
Print pointer value
If you want to print a pointer (i.e. memory location) value, you can use the %p format specifier. This will print the memory address out in hex:
printf("ramon = %p\n", ramon); // Print the "pointer to the pointer to melissa"
printf("ramon = %p\n", *ramon); // Print the "pointer to melissa"
ramon isn't an int, it's a pointer to a pointer to an int. **ramon would be an int. You're trying to print a bunch of ints with %d, but you're mostly trying to print pointers which uses the format %p.
read man printf. It is not clear whether you want to print the value pointed to by ramon or the actual value of ramon which is an address of an pointer to an int. Same for other warnings as well.
The type of the expression ramon is an int **, and the %d specifier expects an int. *ramon will be of type int *, and **ramon will be the desired int.
If you want to print the pointer itself, use the %p specifier.
ramon and paul are pointers and the printf format specifier for printing values of pointers themselves (not what they're pointing to) is %p. Try
printf("ramon = %p\n", ramon);
The warning has nothing to do with how you are initializing your pointers, it has to do with the mismatch in types between printf's %d specifier and the types you are passing to it.
If you want to print a pointer, use %p.
You declared ramon of type "pointer to pointer to type int". i.e. it holds an address to a "pointer to type int". %d on the other hand is the format specifier for int which is why you are getting the errors. Instead try the following:
printf("&paul = %p\n", ramon); //print the address that ramon points to
printf("&melissa = %p\n", *ramon); //print the address that paul points to
printf("&melissa = %p\n", paul); //same as above
printf("melissa = %d\n", **ramon); //print the contents of melissa
printf("melissa = %d\n", *paul); //same as above
printf("melissa = %d\n", melissa); //same as above
Output
&paul = 0xbf8072f4
&melissa = 0xbf8072f0
&melissa = 0xbf8072f0
melissa = 5
melissa = 5
melissa = 5
I reckon this has to do with the way I initialize my pointers
Why would you reckon that when the error message says nothing about initialization? Read it again:
"warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
You have %d in the format string for your printf() call, as a placeholder for the value that you want to print. %d is used as a placeholder for values that are int s. The value you want to print is ramon. That variable has the type int**. The type int and the type int** are not the same.
If you want to print a pointer, then you should write the format string so as to expect a pointer. We format pointers with %p.
but standing at the bottom of a steep learning curve I don't know how to progress.
The way to progress is to read the error and/or warning messages and attempt to understand them. The error messages are talking about types. You should not be trying to do anything with pointers if you haven't first got your head around the concept that values have a type (i.e., what kind of thing they are).