I have a simple program which is supposed to print a string. But I am not getting the expected output. Can anyone tell me what is wrong with the program ?
Here is my code:
main()
{
char arr[] = "Test_string";
printf("%20s"+1,arr);
return 0;
}
output: 20s
Expected output is:Test_string
"Test_string" getting printed in 20 places as we are giving "%20s" as format specifier.
It is very simple if you carefully look at your printf call.
Here is the prototype of printf : int printf(const char *format, ...);.
printf expects a pointer to format string as the first argument. In your program you are passing a pointer to this string : "20s" and printf promptly prints what you are passing.
Let me explain why the pointer passed is pointing to "20s" and not "%20s".
Quoted strings in C are interpreted as character pointers.
Character arrays which, when passed to a function, decay into a pointer.
printf("%20s",arr); is equivalent to :
const char * ptr = "%20s";
printf(ptr,arr);
similarly printf("%20s"+1,arr); is equivalent to :
const char * ptr = "%20s";
printf(ptr+1,arr);
Because you are passing "%20s"+1, the actual pointer which is passed to printf is pointing to a string "20s".
Remove the +1 next to the format string
printf("%20s",arr);
Related
This question already has answers here:
Char pointers and the printf function
(6 answers)
Closed 1 year ago.
For example, the following code returns an error and a warning when compiled and an int when changed to %d
Warning:
format %s expects argument of type char *, but argument 2 has type int
void stringd() {
char *s = "Hello";
printf("derefernced s is %s", *s);
}
*s is an expression of type char since it's the dereference operator applied to a pointer-to-char1. As a result, it gets promoted to an int when passed to printf; in order to print a null-terminated string, you need to pass the pointer to the first character (i.e. just s).
1 even though s is not a const pointer, you should not try to modify the characters it points to as they may be placed in read-only memory where string literals are stored on some architectures/environments; see this discussion for more details.
The variable s is a pointer to the first out of a series of characters which are consecutive in memory (colloquially referred to as a "string", though it's not quite the same). It's a pointer to a character, thus char *.
Dereferencing s (by doing *s) gives you the first of those characters, h, whose type is now just char. One layer of indirection was stripped away.
Thus, the issue is that you're trying to pass a character (char), where a string (char *) was expected. char * was expected because you used the %s type character in your format string to printf. Instead, you should use %c, which expects single, simple char.
The mistake here is actually quite grave. If you were allowed to pass this 'h' where a char * was expected, you would end up with the ASCII code of 'h' (0x68) being passed where a pointer was expected. printf would be none-the-wiser, and would try to dereference that value, treating 0x68 like a pointer to the beginning of a string. Of course, that's probably not a valid memory location in your program, so that should seg-fault pretty reliability, if it were allowed to happen.
char *ptr = "helloworld"; printf(ptr);
Why it is printing helloworld as i haven't used *ptr in printf which should give the value like we use for pointer to an integer.
According to me it should we printf(*ptr) in printf
For any pointer or array p and index i, the expression p[i] is exactly equal to *(p + i).
If the index i is zero, then we have p[0] being exactly equal to *(p + 0). Adding zero to anything is a no-operation, so it's *(p). And the parentheses are not needed here which gives us *p.
So in your case *ptr would be the same as ptr[0], which is the first character in the string. And only the first character in the string, with the type char.
A "string" is a null-terminated sequence of characters, and to use it we have a pointer to the first character. Which is what plain ptr (without dereference) is. And that matches the printf format string argument, which needs to be a pointer to the first character in the null-terminated string.
printf expects its first argument to be a pointer to char:
7.21.6.3 The printf function
Synopsis
1 #include <stdio.h>
int printf(const char * restrict format, ...);
C 2011 Online Draft
so
printf( ptr );
is correct1. However, the usual practice for printing a plain text string is to do something like
printf( "%s\n", ptr );
rather than passing it as the format string. Alternately, you could use the puts function:
puts( ptr );
since no formatting is involved.
The value in ptr is the address of the first character of the string - printf will print the sequence of characters starting at that address until it sees the string terminator2.
You can pass a char * argument to a function that expects a const char *, but not the other way around; you'll get a diagnostic on the order of "argument n discards const" or something like that. The restrict keyword in the function declaration is basically an optimization hint - you don't need to worry about that right now.
If it sees a conversion specifier in the format string like %d or %f, it will take the value of the corresponding argument and format it as the equivalent sequence of characters.
I was trying to learn pointers and I wrote the following code to print the value of the pointer:
#include <stdio.h>
int main(void) {
char *p = "abc";
printf("%c",*p);
return 0;
}
The output is:
a
however, if I change the above code to:
#include <stdio.h>
int main(void) {
char *p = "abc";
printf(p);
return 0;
}
I get the output:
abc
I don't understand the following 2 things:
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
as per my understanding (which is very little), *p points to a contiguous block of memory that contains abc. I expected both outputs to be the same, i.e.
abc
are the different outputs because of the different ways of printing?
Edit 1
Additionally, the following code produces a runtime error. Why so?
#include <stdio.h>
int main(void) {
char *p = "abc";
printf(*p);
return 0;
}
For your first question, the printf function (and family) takes a string as first argument (i.e. a const char *). That string could contain format codes that the printf function will replace with the corresponding argument. The rest of the text is printed as-is, verbatim. And that's what is happening when you pass p as the first argument.
Do note that using printf this way is highly unrecommended, especially if the string is contains input from a user. If the user adds formatting codes in the string, and you don't provide the correct arguments then you will have undefined behavior. It could even lead to security holes.
For your second question, the variable p points to some memory. The expression *p dereferences the pointer to give you a single character, namely the one that p is actually pointing to, which is p[0].
Think of p like this:
+---+ +-----+-----+-----+------+
| p | ---> | 'a' | 'b' | 'c' | '\0' |
+---+ +-----+-----+-----+------+
The variable p doesn't really point to a "string", it only points to some single location in memory, namely the first character in the string "abc". It's the functions using p that treat that memory as a sequence of characters.
Furthermore, constant string literals are actually stored as (read-only) arrays of the number of character in the string plus one for the string terminator.
Also, to help you understand why *p is the same as p[0] you need to know that for any pointer or array p and valid index i, the expressions p[i] is equal to *(p + i). To get the first character, you have index 0, which means you have p[0] which then should be equal to *(p + 0). Adding zero to anything is a no-op, so *(p + 0) is the same as *(p) which is the same as *p. Therefore p[0] is equal to *p.
Regarding your edit (where you do printf(*p)), since *p returns the value of the first "element" pointed to by p (i.e. p[0]) you are passing a single character as the pointer to the format string. This will lead the compiler to convert it to a pointer which is pointing to whatever address has the value of that single character (it doesn't convert the character to a pointer to the character). This address is not a very valid address (in the ASCII alphabet 'a' has the value 97 which is the address where the program will look for the string to print) and you will have undefined behavior.
p is the format string.
char *p = "abc";
printf(p);
is the same as
print("abc");
Doing this is very bad practice because you don't know what the variable
will contain, and if it contains format specifiers, calling printf may do very bad things.
The reason why the first case (with "%c") only printed the first character
is that %c means a byte and *p means the (first) value which p is pointing at.
%s would print the entire string.
char *p = "abc";
printf(p); /* If p is untrusted, bad things will happen, otherwise the string p is written. */
printf("%c", *p); /* print the first byte in the string p */
printf("%s", p); /* print the string p */
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
With your code you told printf to use your string as the format string. Meaning your code turned equivalent to printf("abc").
as per my understanding (which is very little), *p points to a contiguous block of memory that contains abc. I expected both outputs to be the same
If you use %c you get a character printed, if you use %s you get a whole string. But if you tell printf to use the string as the format string, then it will do that too.
char *p = "abc";
printf(*p);
This code crashes because the contents of p, the character 'a' is not a pointer to a format string, it is not even a pointer. That code should not even compile without warnings.
You are misunderstanding, indeed when you do
char *p = "Hello";
p points to the starting address where literal "Hello" is stored. This is how you declare pointers. However, when afterwards, you do
*p
it means dereference p and obtain object where p points. In our above example this would yield 'H'. This should clarify your second question.
In case of printf just try
printf("Hello");
which is also fine; this answers your first question because it is effectively the same what you did when passed just p to printf.
Finally to your edit, indeed
printf(*p);
above line is not correct since printf expects const char * and by using *p you are passing it a char - or in other words 'H' assuming our example. Read more what dereferencing means.
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
"abc" is your format specifier. That's why it's printing "abc". If the string had contained %, then things would have behaved strangely, but they didn't.
printf("abc"); // Perfectly fine!
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
%c is the character conversion specifier. It instructs printf to only print the first byte. If you want it to print the string, use...
printf ("%s", p);
The %s seems redundant, but it can be useful for printing control characters or if you use width specifiers.
The best way to understand this really is to try and print the string abc%def using printf.
The %c format specifier expects a char type, and will output a single char value.
The first parameter to printf must be a const char* (a char* can convert implicitly to a const char*) and points to the start of a string of characters. It stops printing when it encounters a \0 in that string. If there is not a \0 present in that string then the behaviour of that function is undefined. Because "abc" doesn't contain any format specifiers, you don't pass any additional arguments to printf in that case.
#include<stdio.h>
int main(void) {
char a = "any"; //any string
printf("%c", a);
getch();
}
Why always d (for %c) or 100 (for %d) gets printed? What's happening?
char a="any"; is not declaring any string. Your compiler should through error/warning. You need
const char *a = "any";
Now
printf("%c", *a);
will print character a as pointer a is pointer to the first element of the string literal any.
Your code has issues. On
char a="any";
the string literal "any" is a pointer but you are saving it in a (small) integer type. Because the value of a is (part of) an address it will have an essentially arbitrary value. On my machine it prints "T" (if I remove the getch() line because that doesn't compile).
GCC gives the following warning:
warning: initialization makes integer from pointer without a cast
and whatever compiler you are using probably tells you something similar. You should really take this warning seriously.
"something between double quotes"
Allocates memory for the string and returns a pointer to the string in memory. you need to store this pointer in a using char *a = "abc"; now 'a' is a pointer to the string abc.
printf("%s",a) this will print the entire string abc.
for a single character use single quotes 'a' in this case char a = 'b'; is correct.
printf("%c",a) this will print b.
printf("%d",a) this will print the ascii value of 'b', which is 98
In the statement
char a = "any";
the string literal "any" evaluates to the address of its first character which is of type const char *. Assigning a const char * to a char variable implicitly converts the pointer to an integer. This emits the following warning if you compile with -W gcc flag:
warning: initialization makes integer from pointer without a cast [enabled by default]
What happens next is the least significant byte of the cast integer value is assigned to the char variable a. This is a random value and cannot be predicted. On my machine, it happened to be the ascii code for the character /. On your machine, it happened to be 100, the ascii code for the character d. It is just pure chance. Nothing else.
You should assign a string literal to a const char * as:
const char *a = "any";
and print the string pointed to by a by the %s conversion specifier as:
printf("%s\n", a);
Also note that getch is not a C standard library function, so your program won't compile on a linux machine. You can use getchar for the same effect, though.
Can anyone explain to me what I don't understand here please?
I am trying to pass the argument as a "string" (i know there are no strings in c) so that I can use that string later with other functions like it's a file name that has to be passed for example.
But I don't know why it won't accept it or what type should it be
#include <stdio.h>
int main ( int argc, char *argv[] )
{
char *array= argv[0];
foo(*array);
}
void foo( char *array)
// notice the return type - it's a pointer
{
printf(array);
}
thanks alot!
You should be calling the function like this:
foo(array);
What you're doing is dereferencing the pointer, which returns a char, which is the first character in the string.
Your printf call should also look like this:
printf("%s", array);
Your entire fixed code should look like the following:
#include <stdio.h>
void foo(char *array)
{
printf("%s", array);
}
int main ( int argc, char *argv[] )
{
// TODO: make sure argv[1] exists
char *array= argv[1];
foo(array);
}
When you say foo (*array), you're decaying the array into a pointer to the first element, in order to dereference that element, giving you the first character. That's what you're trying to pass to the function. Leave out the asterisk and just pass array for it to decay into the pointer you need.
The other issue is that you're not using printf correctly. First of all, here's a reference. You need to pass a string of tokens that tell the compiler what type of argument to expect next because it has no way of telling. In your case, your string would contain "%s" to tell it to expect a char *, and then you'd pass array as that char * argument.
printf ("The string is %s", array);
argv is a array of character pointers, that means argv is going to store the address of all the strings which you passed as command line argument.
so argv[0] will gives you the address of first string which you passed as command line argument, that you are storing into the pointer variable array in main function.
Now you have to pass only the address to the function foo but you are passing the first character of that string. For example if your first command line argument is temp.txt you are passing character t to the function foo. So inside foo function you are having a char pointer variable array, in that ASCII value of the character t will be assigned. And then you are passing that to printf, which will treads that ASCII value as address, and it will tries to access that address to print which will leads to crash (unexpected behaviour).
So you have to pass only the address of the command line argument to the function foo like below.
foo(array);
printf(array) - Here printf will treads the format specifier as string(%s) and it will tries to print all the characters starting from the address array untill it meets a null character \0.
But better to add the printf like below
printf("%s", array);