Problems about C program char * pointer - c

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);

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 output of the following code in C? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Please take a look at this code.
#include <stdio.h>
int main()
{
char *p;
p = "%d";
p++;
p++;
printf(p-2,23);
return 0;
}
I have the following questions
1) How can a pointer to a character data type can hold a string data type?
2) What happens when p is incremented twice?
3) How can the printf()can print a string when no apparent quotation marks are used?
"How can a pointer to a character data type can hold a string data type?" Well, it's partly true that in C, type 'pointer to char' is the string type. Any function that operates on strings (including printf) will be found to accept these strings via parameters of type char *.
"How can printf() print a string when no apparent quotation marks are used?" There's no rule that says you need quotation marks to have a string! That thing with quotation marks is a string constant or string literal, and it's one way to get a string into your program, but it's not at all the only way. There are lots of ways to construct (and manipulate, and modify) strings that don't involve any quotation marks at all.
Let's draw some pictures representing your code:
char *p;
p is a pointer to char, but as you correctly note, it doesn't point anywhere yet. We can represent it graphically like this:
+-----------+
p: | ??? |
+-----------+
Next you set p to point somewhere:
p = "%d";
This allocates the string "%d" somewhere (it doesn't matter where), and sets p to point to it:
+---+---+---+
| % | d |\0 |
+---+---+---+
^
|
\
\
\
|
+-----|-----+
p: | * |
+-----------+
Next, you start incrementing p:
p++;
As you said, this makes p point one past where it used to, to the second character of the string:
+---+---+---+
| % | d |\0 |
+---+---+---+
^
|
|
|
|
|
+-----|-----+
p: | * |
+-----------+
Next,
p++;
Now we have:
+---+---+---+
| % | d |\0 |
+---+---+---+
^
|
/
/
/
|
+-----|-----+
p: | * |
+-----------+
Next you called printf, but somewhat strangely:
printf(p-2,23);
The key to that is the expression p-2. If p points to the third character in the string, then p-2 points to the first character in the string:
+---+---+---+
| % | d |\0 |
+---+---+---+
^ ^
+----|----+ |
p-2: | * | /
+---------+/
/
|
+-----|-----+
p: | * |
+-----------+
And that pointer, p-2, is more or less the same pointer that printf would have received if you're more conventionally called printf("%d", 23).
Now, if you thought printf received a string, it may surprise you to hear that printf is happy to receive a char * instead — and that in fact it always receives a char *. If this is surprising, ask yourself, what did you thing printf did receive, if not a pointer to char?
Strictly speaking, a string in C is an array of characters (terminated with the '\0' character). But there's this super-important secret fact about C, which if you haven't encountered yet you will real soon (because it's really not a secret at all):
You can't do much with arrays in C. Whenever you mention an array in an expression in C, whenever it looks like you're trying to do something with the value of the array, what you get is a pointer to the array's first element.
That pointer is pretty much the "value" of the array. Due to the way pointer arithmetic works, you can use pointers to access arrays pretty much transparently (almost as if the pointer was the array, but of course it's not). And this all applies perfectly well to arrays of (and pointers to) characters, as well.
So since a string in C is an array of characters, when you write
"%d"
that's an array of three characters. But when you use it in an expression, what you get is a pointer to the array's first element. For example, if you write
printf("%d", 23);
you've got an array of characters, and you're mentioning it in an expression, so what you get is a pointer to the array's first element, and that's what gets passed to printf.
If we said
char *p = "%d";
printf(p, 23);
we've done the same thing, just a bit more explicitly: again, we've mentioned the array "%d" in an expression, so what we get as its value is a pointer to its first element, so that's the pointer that's used to initialize the pointer variable p, and that's the pointer that gets passed as the first argument to printf, so printf is happy.
Up above, I said "it's partly true that in C, type 'pointer to char' is the string type". Later I said that "a string in C is an array of characters". So which is it? An array or a pointer? Strictly speaking, a string is an array of characters. But like all arrays, we can't do much with an array of characters, and when we try, what we get is a pointer to the first element. So most of the time, strings in C are accessed and manipulated and modified via pointers to characters. All functions that operate on strings (including printf) actually receive pointers to char, pointing at the strings they'll manipulate.
the following explains each statement in the posted code:
#include <stdio.h>// include the header file that has the prototype for 'printf()'
int main( void ) // correct signature of 'main' function
{
char *p; // declare a pointer to char, do not initialize
p = "%d"; // assign address of string to pointer
p++; // increment pointer (so points to second char in string
p++; // increment pointer (so points to third char in string
printf(p-2,23);// use string as 'format string' in print statement,
// and pass a parameter of 23
return 0; // exit the program, returning 0 to the OS
}
1) How can a pointer to a character data type can hold a string data type?
Ans: String is not a basic data type in C. String is nothing but a continuous placement of char in memory until '\0' is encountered.
2) What happens when p is incremented twice?
Ans: It now points to the '\0' character.
3) How can the printf()can print a string when no apparent quotation marks are used
Ans: A string is always represented in quotation marks so extra quotes are not needed.
1. How can a pointer to a character data type can hold a string data type?
-> Char pointer will hold the address of char datatype, since string is collection of char datatypes. Hence char pointer can hold the string data type..
2. What happens when p is incremented twice?
-> When you assign the char pointer to string pointer will point to first char. So when you increment the pointer twice, it will hold the address of 3rd char, in your case it is'\0';
3. How can the printf()can print a string when no apparent quotation marks are used?
-> printf(p-2,23); Uses string as format identifier in your case it is "%d".

%s format is used to find address of a string

#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;
}

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.

Why can I store a string in the memory address of a char?

I'm starting to understand pointers and how to dereference them etc. I've been practising with ints but I figured a char would behave similarly. Use the * to dereference, use the & to access the memory address.
But in my example below, the same syntax is used to set the address of a char and to save a string to the same variable. How does this work? I think I'm just generally confused and maybe I'm overthinking it.
int main()
{
char *myCharPointer;
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
myCharPointer = "This is a string.";
printf("%s\n", myCharPointer);
return 0;
}
First, you need to understand how "strings" work in C.
"Strings" are stored as an array of characters in memory. Since there is no way of determining how long the string is, a NUL character, '\0', is appended after the string so that we know where it ends.
So for example if you have a string "foo", it may look like this in memory:
--------------------------------------------
| 'f' | 'o' | 'o' | '\0' | 'k' | 'b' | 'x' | ...
--------------------------------------------
The things after '\0' are just stuff that happens to be placed after the string, which may or may not be initialised.
When you assign a "string" to a variable of type char *, what happens is that the variable will point to the beginning of the string, so in the above example it will point to 'f'. (In other words, if you have a string str, then str == &str[0] is always true.) When you assign a string to a variable of type char *, you are actually assigning the address of the zeroth character of the string to the variable.
When you pass this variable to printf(), it starts at the pointed address, then goes through each char one by one until it sees '\0' and stops. For example if we have:
char *str = "foo";
and you pass it to printf(), it will do the following:
Dereference str (which gives 'f')
Dereference (str+1) (which gives 'o')
Dereference (str+2) (which gives another 'o')
Dereference (str+3) (which gives '\0' so the process stops).
This also leads to the conclusion that what you're currently doing is actually wrong. In your code you have:
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
When printf() sees the %s specifier, it goes to address pointed to by myCharPointer, in this case it contains 'G'. It will then try to get next character after 'G', which is undefined behaviour. It might give you the correct result every now and then (if the next memory location happens to contain '\0'), but in general you should never do this.
Several comments
Static strings in c are treated as a (char *) to a null terminated
array of characters. Eg. "ab" would essentially be a char * to a block of memory with 97 98 0. (97 is 'a', 98 is 'b', and 0 is the null termination.)
Your code myCharPointer = &charMemoryHolder; followed by printf("%s\n", myCharPointer) is not safe. printf should be passed a null terminated string, and there's no guarantee that memory contain the value 0 immediately follows your character charMemoryHolder.
In C, string literals evaluate to pointers to read-only arrays of chars (except when used to initialize char arrays). This is a special case in the C language and does not generalize to other pointer types. A char * variable may hold the address of either a single char variable or the start address of an array of characters. In this case the array is a string of characters which has been stored in a static region of memory.
charMemoryHolder is a variable that has an address in memory.
"This is a string." is a string constant that is stored in memory and also has an address.
Both of these addresses can be stored in myCharPointer and dereferenced to access the first character.
In the case of printf("%s\n", myCharPointer), the pointer will be dereferenced and the character displayed, then the pointer is incremented. It repeasts this until finds a null (value zero) character and stops.
Hopefully you are now wondering what happens when you are pointing to the single 'G' character, which is not null-terminated like a string constant. The answer is "undefined behavior" and will most likely print random garbage until it finds a zero value in memory, but could print exactly the correct value, hence "undefined behavior". Use %c to print the single character.

Resources