%s format is used to find address of a string - c

#include<stdio.h>
void main()
{
char a[]="get organized learn c!";
printf("%s",&a[2]);
}
I got the output:
t organized learn c!
it should give error because i used & for %s

No, your code is behaving correctly.
a is an array of type char. It is compatible with char *
a[2] is a single char
&a[2] is a char * which points to the third character in the array. It is equivalent to a + 2.

It should not give an error - the printf in the code works correctly.
You cannot look at the address-of & operator alone, and decide that the result it produces is invalid, because the rest of the expression is important, too. In your case, & operator is applied to a[2], so it takes the address of the third character in the string. This is valid, as long as your null-terminated string has at least two characters, which your string does.
get organized learn c!\0
^ ^ ^
| | +- null terminator
| +---------------------- &a[2] points here
+------------------------ a, interpreted as a pointer, points here
As you can see, both a and &a[2] point to valid null-terminated C strings. In your case, strings overlap, but C does not prohibit it.

The error is not where you expect:
The prototype for main without arguments should be int main(void)
For good style, main should return 0 explicitly.
For a conversion specifier %s, printf expects a pointer to a null terminated string. &a[2] is the address of the third byte in a, which is a valid char pointer into a, namely to the null terminated string "t organized learnc!", no error here.
You could have written a + 2 or 2 + a or even &2[a] with the same exact meaning.
#include <stdio.h>
int main(void) {
char a[] = "get organized learn c!";
printf("%s\n", &a[2]);
return 0;
}

Related

Are pointers or memory addresses can be parameters in printf() function?

I got confused making a printing function.
void Printing(int* pi, char* pa)
{
printf("%d", *pi);
printf("%s", *pa);
}
Code above has an error in 2nd printf().
But code below doesn't have. It prints the integer and string well.
void Printing(int* pi, char* pa)
{
printf("%d", *pi);
printf("%s", pa);
}
So far, I gave variables to printf(). But I don't understand why I need to give the pointer to the 2nd printf().
In your code
printf("%s", *pa);
should be
printf("%s", pa);
as %s expects the starting address of a null-terminated character array (i.e., a pointer, not the char as you have supplied).
From C11, chapter 7.21.6.1 The fprintf
s
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type. Characters from the array are written up to (but not including) the terminating null character. [...]
To add, *pa is same as pa[0], which is of type char. To print that, you'd need to use %c conversion specifier.
But I don't understand why I need to give the pointer to the 2nd printf().
Because strings work a little weirdly in C. Technically, there is no type for strings in C. So const char */char * is used for strings. The way this works is that the pointer points to the beginning of the string, and the string ends with a NUL character '\0'. To visualize it, say you call Printing with Printing(0, "Hello");, you pass a pointer to the beginning of a string literal which looks like this in memory:
+---+---+---+---+---+---+
| H | e | l | l | o |END|
+---+---+---+---+---+---+
And the pointer you pass points to the first character, H. If you understand this, you will understand why it needs a pointer. If you dereference it, you will only give the first character H, so it won't be able to print the whole string.

what is the explaination of the output of the given program

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.

Char pointers and the printf function

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.

Problems about C program char * pointer

There is a simple C program.
#include<stdio.h>
int main()
{
char *s = "abcde";
printf("%s\n", s);
printf("%s\n", *s); /* This is wrong */
return 0;
}
This is my thought:
variable s is a char * pointer to the string abcde. So variable s is a memory address , and the memory address store the string abced.
The %s format string in function printf() is formatting a string. I don't know why s is the string. The variable s is a char * pointer and *s is the string of abcde, isn't it?
In C, "strings" are NUL-terminated arrays of characters.
The code char *s = "abcde"; does two things:
First, it allocates (in read-only program data) some (unnamed) memory, and populates it with "abcde":
1000 1001 1002 1003 1004 1005
_________________________________________
| a | b | c | d | e | \0 |
|______|______|______|______|______|______|
Then, in the stack frame of main, a pointer to char is allocated, named s, and its value is initialized with the address of your string. In my example, s = 1000.
1000 1001 1002 1003 1004 1005
_________________________________________
| a | b | c | d | e | \0 |
|______|______|______|______|______|______|
^
|
|
s = 1000
The %s format specifier tells printf to expect the address of a NUL-terminated string as the corresponding argument..
When you pass s, you are doing just that: telling printf that your string lives at address 1000. printf goes to that address, and starts reading the characters there (a, b, c...) until it encounters a NUL ('\0') character, at which point it stops. It has now read your string.
When you pass *s, two things happen. First, the program de-references the pointer. Since it is a pointer-to-char, that means it reads one character from the memory at 1000. The result of this is 'a', which is the decimal number 97. Now, this value is passed to printf (as before), and printf still thinks it's an address. However, 97 is an invalid address, and your program crashes.
If you need to brush up on your understanding of pointers:
How do pointer to pointers work in C?
Everything you need to know about pointers in C
Pointer Basics
and *s is the string of abcde, isn't it?
No. *s is a char, the first char in the string, so it's a. *(s + 1) is b, *(s + 2) is c, and so on. A char* is an address which points, or refers, to some number of chars.
You are lying to printf with that second call and invoking undefined behavior. The character a is passed and interpreted as an address using it's integral value. That's going to lead to bad things.
printf expects a pointer to char when you use the %s format specifier and that's what you have to pass it. So, what ends up happening is that printf reads past (char*)'a' looking for a null terminator. It may or may not find one before segfaulting, but it's UB either way.
Turn your warnings on.
In c, a string is just a string of characters in memory terminated with a null character ('\0') which tells you where the string stops. There are no string objects. As such when you provide a 'string' to printf you pass it a pointer to where the string is held and it figures out the rest.
when printf meet with a string , It automatically put out the string from start address "a" to the end "\0"; This is special. While printf deal with string, it obey this rule. And for a string, "*a" is the first character of the string , not the whole string . So when you want to put out a string , give the start address to printf. "a"."(a+1)"...can help you put out the character you want in the string.
Q: The variable s is a char * pointer and *s is the string of abcde, isn't it?
No.
*s is a specific character pointed to by s. In the question code, it is the character 'a'.
If it helps, *s results in the same character as s[0]. In otherwords, (for the question code) *s is the value of the first character in the array (or string) of characters.
On the other hand, s is a char * that can store an address. It can store any address in memory you like. In the question code, s was initialized to point at a specific static string (or array of characters).
You can print the specific address pointed to by s:
printf("s points to %p\n", s);
You can print the specific character pointed to by s:
printf("The character pointed to by s: %c\n", *s);
You can print the string (or array) of characters pointed to by s:
printf("s points to an array of characters: %s", s);

pointer of char and int

Hi I have a simple question
char *a="abc";
printf("%s\n",a);
int *b;
b=1;
printf("%d\n",b);
Why the first one works but the second one doesnot work?
I think the first one should be
char *a="abc";
printf("%s\n",*a);
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
Thanks
Ying
Why the first one works but the second one doesnot work?
Because in the first, you're not asking it to print a character, you're asking it to print a null-terminated array of characters as a string.
The confusion here is that you're thinking of strings as a "native type" in the same way as integers and characters. C doesn't work that way; a string is just a pointer to a bunch of characters ending with a null byte.
If you really want to think of strings as a native type (keeping in mind that they really aren't), think of it this way: the type of a string is char *, not char. So, printf("%s\n", a); works because you're passing a char * to match with a format specifier indicating char *. To get the equivalent problems as with the second example, you'd need to pass a pointer to a string—that is, a char **.
Alternatively, the equivalent of %d is not %s, but %c, which prints a single character. To use it, you do have to pass it a character. printf("%c\n", a) will have the same problem as printf("%d\n", b).
From your comment:
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
This is where the loose thinking of strings as native objects falls down.
When you write this:
char *a = "abc";
What happens is that the compiler stores a array of four characters—'a', 'b', 'c', and '\0'—somewhere, and a points at the first one, the a. As long as you remember that "abc" is really an array of four separate characters, it makes sense to think of a as a pointer to that thing (at least if you understand how arrays and pointer arithmetic work in C). But if you forget that, if you think a is pointing at a single address that holds a single object "abc", it will confuse you.
Quoting from the GNU printf man page (because the C standard isn't linkable):
d, i
The int argument is converted to signed decimal notation …
c
… the int argument is converted to an unsigned char, and the resulting character is written…
s
… The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0') …
One last thing:
You may be wondering how printf("%s", a) or strchr(a, 'b') or any other function can print or search the string when there is no such value as "the string".
They're using a convention: they take a pointer to a character, and print or search every character from there up to the first null. For example, you could write a print_string function like this:
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
Or:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
Either way, you're assuming the char * is a pointer to the start of an array of characters, instead of just to a single character, and printing each character in the array until you hit a null character. That's the "null-terminated string" convention that's baked into functions like printf, strstr, etc. throughout the standard library.
Strings aren't really "first-class citizens" in C. In reality, they're just implemented as null-terminated arrays of characters, with some syntactic sugar thrown in to make programmers' lives easier. That means when passing strings around, you'll mostly be doing it via char * variables - that is, pointers to null-terminated arrays of char.
This practice holds for calling printf, too. The %s format is matched with a char * parameter to print the string - just as you've seen. You could use *a, but you'd want to match that with a %c or an integer format to print just the single character pointed to.
Your second example is wrong for a couple of reasons. First, it's not legal to make the assignment b = 1 without an explicit cast in C - you'd need b = (int *)1. Second, you're trying to print out a pointer, but you're using %d as a format string. That's wrong too - you should use %p like this: printf("%p\n", (void *)b);.
What it really looks like you're trying to do in the second example is:
int b = 1;
int *p = &b;
printf("%d\n", *p);
That is, make a pointer to an integer, then dereference it and print it out.
Editorial note: You should get a good beginner C book (search around here and I'm sure you'll find suggestions) and work through it.

Resources