In the following code:
#include <stdio.h>
int main(void) {
char* message = "Hello C Programmer!";
printf("%s", message);
return 0;
}
I don't fully understand why it wasn't necessary to prepend an '*' to message in the printf call. I was under the assumption that message, since it is a pointer to a char, the first letter in the double quoted string, would display the address of the 'H'.
The %s format operator requires its corresponding argument to be a char * pointer. It prints the entire string that begins at that address. A string is a sequence of characters ending with a null byte. That's why this prints the entire message.
If you supply an array as the corresponding argument, it's automatically converted to a pointer to the first character of the array. In general, whenever an array is used as an r-value, it undergoes this conversion.
You don't need to use the * operator because the argument is supposed to be a pointer. If you used *message you would only pass the 'H' character to printf(). You would do this if you were using the %c format instead of %s -- its corresponding argument should be a char.
You're right that message is a pointer, of type "pointer to char", or char *. So if you were trying to print a character (an individual character), you would certainly have needed a *:
printf("first character: %c\n", *message);
In a printf format specifier, %c expects a character, which is what *message gives you.
But you weren't trying to print a single character, you were trying to print the whole string. And in a printf format specifier, %s expects a pointer to a character, the first of usually several characters to print. So
printf("entire string: %s\n", message);
is correct.
The conversion specifier %s is used to output strings (a sequence of characters terminated with the zero character '\0') pointers to first characters of which are passed to the function printf as an argument.
You can imagine that the function internally executes the following loop
for ( ; *message != '\0'; ++message )
{
printf( "%c", *message );
}
If you will supply the expression *message then it has type char and the function printf will try to interpret its value that is character 'H' as a value of a pointer. As result the function call will have undefined behavior.
To output the value of the pointer message you should use the conversion specifier %p like
printf( "%p", message );
Or as an integer value as for example
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
char *message = "Hello C Programmer!";
printf( "The value of the pointer message is %" PRIiPTR "\n", ( intptr_t )message );
return 0;
}
In addition, a pointer must be used here.
If you passed a character, it would be passed by value, and printf would lose the original address of the character. That means it would no longer be possible to access the characters that come after the first.
You need to pass a pointer by value to ensure you're retaining the original address of the head of the string.
Related
I am looking to learn C and having a really hard time grasping the concepts of string pointers (and just pointers in general).
I have the following program:
#include<stdio.h>
#include<string.h>
int main()
{
// char test[6] = "hello";
char *test = "hello"; // test is a pointer to 'h'
int size_of_test_pt = sizeof(test); // this is the size of a pointer? which is 8 bytes.
int size_of_test = sizeof(*test); // this is the size of h, which is 1.
printf("\nSize of pointer to test: %d\n", size_of_test_pt); // prints 8
printf("\nSize of test: %d\n", size_of_test); // prints 1
printf("\nPrint %s\n", test); // why does this print 'hello', I thought test was a pointer?
printf("\nPrint %c\n", *test); // this is printing the first character of hello, I thought this would print hello.
printf("\nPrint %i\n", *test); // this prints 104...is this ASCII for h
return 0;
}
Everything makes sense until the last 3 print statements. If test is a pointer variable. Why does printf print out the word "hello" rather than an address?
For the printf("\nPrint %c\n", *test) call is it the right understanding that I am dereferencing test, which is an address and accessing the first element, then printing it to the screen?
The conversion specifier %s is designed to output strings and it expects as an argument a pointer expression of the type char * or const char * that points to the first character of a string that to be outputted.
In this case the function outputs all characters starting from the address pointed to by the supplied pointer until the terminating zero character '\0' is encountered.
If you want to output the value of such a pointer you need to write
printf("\nPrint %p\n", ( void * )test);
The conversion specifier %c is designed to output a single object of the type char.
Pay attention to that the pointer test points to the first character of the string literal "hello". So dereferencing the pointer you will get the first character of the string literal.
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
char *test = "hello";
for ( ; *test != '\0'; ++test )
{
printf( "%c ", *test );
}
putchar( '\n' );
}
The program output is
h e l l o
The string literal is stored in memory as a character array containing the following elements
{ 'h', 'e', 'l', 'l', 'o', '\0' }
If test is a pointer variable. Why does printf print out the word "hello" rather than an address?
In short, it's because the %s expects its parameter to be of type char *.
For the printf("\nPrint %c\n", *test) call is it the right understanding that I am dereferencing test, which is an address and accessing the first element, then printing it to the screen?
Yes. The %c format specifier expects its parameter to be a char, and that's exactly what you get when you dereference a pointer to char. Furthermore, it knows to print that value as a character. In the following line, the %i parameter expects value of type int, and since char is a kind of int, it accepts that and prints the numeric value of the character (h) that you provided.
In C a "string" is a sequence of characters, e.g. h, e, l, l, o. To indicate that the sequence is ending, the special value 0 is appended to the sequence.
If there were no such things as pointers, passing a string to a function would involve copying the entire sequence of characters. This is normally not practical, so instead we just pass on a reference (i.e. a pointer) telling where to find the first character of the string.
This is so commonly used that the pointer itself is sometimes referred to as a string even though it is really a pointer to a string. The string itself is the sequence of characters.
Think of a pointer like a bibliographic reference identifying a particular book. Including such a reference in a text is much more practical than inserting a copy of the entire book.
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.
why codeblocks crashes when I try to run this code :
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
char *ch= "Sam smith";
printf("%s\n",*ch);
}
but it works fine when I remove *ch in printf and replace it with just ch like this
void main(void)
{
char *ch= "Sam smith";
printf("%s\n",ch);
}
shouldn't *ch mean the content of the address pointed to by ch which is the string itself, and ch mean the adress of the first element in the string? so i expected the opposite!
I use Code blocks 17.12, gcc version 5.1.0, on windows 8.1 .
*ch dereferences the pointer to yield the data it points to. Here the first character of the string.
Providing the wrong specifier to printf is undefined behaviour (passing a value where printf expects a pointer)
printf("%c\n",*c);
would print the first character, without crashing. If you want to print all the string using %c (or use putchar), loop on the characters. But that's what %s does.
As a side note, better use const to reference literal strings so no risk to attempt to modify them:
const char *ch= "Sam smith";
why codeblocks crashes when I try to run this code :
char *ch= "Sam smith";
printf("%s\n",*ch);
ch is of type char *.
The %s conversion specifier expects a char *.
You pass *ch, which is the dereferenced ch, i.e. of type char.
If conversion specifiers do not match the types of the arguments, bad things (undefined behavior) happens.
shouldn't *ch mean the content of the address pointed to by ch which is the string itself
There is no data type "string" in C, and thus no "pointer to string".
A "string", in C parlance, is an array of characters, or a pointer to an array of characters, with a null-byte terminator.
ch is a char *, a pointer to the first character of that array - a string, so to speak.
*ch is a char, the first character of that array.
In C, You do not dereference a pointer to a string, when you want to use the whole string the pointer points to. This dereferencing process would result in the first character of the respective string, which is not what you want.
Furthermore, it is undefined behavior if a conversion specifier does not match to the type of the relative argument.
Thus,
printf("%s\n",*ch);
is wrong. *ch is the first character in the string, in this case S, of type char but the %s conversion specifier expects an argument of type *char.
printf("%s\n",ch);
is correct. ch is of type *char as required by the conversion specifier %s.
So, Codeblocks "crashes" apparently because of the mismatching argument type.
main()
{
char str[][3]={"ab","cd","ef","gh"};
printf("\n%s\n%s",str[2][0],&str[0][0]);
//WHY WE NEED TO PUT "&" TO PRINT &str[2][0] the element.
}
//while this works properly
main()
{
char str[][3]={"ab","cd","ef","gh"};
printf("\n%s\n%s",str[2],&str[0]);
}
str[2] is the third element of array str. It is in turn a character array that has type char[3]. In function call like this
printf( "%s", str[2] );
the array is converted to pointer to its first character (element). The first character of array str[2] can be gotten like str[2][0]. So its address is determined like &str[2][0].
Thus expressions str[2] and &str[2][0] are equivalent.
As for this call
printf("\n%s\n%s",str[2],&str[0]);
then it is invalid. Format specifier %s expects an argument of type char * while the type of expression &str[0] is char **. However because in any case expression &str[0] has the value that is the address of the first element of array str[0] the function produces the correct result.
If you want to ouput only a single character instead of a string you have to use format specifier %c For example
printf("\n%c\n%s",str[2][0],&str[0][0]);
^^^
In this function call as str[2][0] is a single character then there is used format specifier %c for its output.
I am thinking of something like:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(void) {
//test pointer to string
char s[50];
char *ptr=s;
printf("\nEnter string (s): ");
fgets(s, 50, stdin);
printf("S: %s\nPTR: %s\n", s, *ptr);
system("PAUSE");
return 0;
}
Or should I use a for loop with *(s+i) and the format specifier %c?
Is that the only possible way to print a string through a pointer and a simple printf?
Update: The printf operates with the adress of the first element of the array so when I use *ptr I actually operate with the first element and not it's adress. Thanks.
The "%s" format specifier for printf always expects a char* argument.
Given:
char s[] = "hello";
char *p = "world";
printf("%s, %s\n", s, p);
it looks like you're passing an array for the first %s and a pointer for the second, but in fact you're (correctly) passing pointers for both.
In C, any expression of array type is implicitly converted to a pointer to the array's first element unless it's in one of the following three contexts:
It's an argument to the unary "&" (address-of) operator
It's an argument to the unary "sizeof" operator
It's a string literal in an initializer used to initialize an array object.
(I think C++ has one or two other exceptions.)
The implementation of printf() sees the "%s", assumes that the corresponding argument is a pointer to char, and uses that pointer to traverse the string and print it.
Section 6 of the comp.lang.c FAQ has an excellent discussion of this.
printf("%s\n", ptr);
Is this what you want?
By the way, from printf(3), here's the documentation for the s conversion specifier (i.e %s):
If no l modifier is present: 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'); if a precision is specified, no more
than the number specified are written. If a precision is given, no
null byte need be present; if the precision is not specified, or is
greater than the size of the array, the array must contain a
terminating null byte.
you should do "printf("S: %s\nPTR: %s\n", s, ptr);
" instead of printf("S: %s\nPTR: %s\n", s, *ptr);
difference between ptr and *ptr is: ptr gives you the address in the memory of the variable you are pointing to and *ptr gives rather the value of the pointed variable In this case is *ptr = ptr[0]
this code will show what i mean:
printf("\tS: %s\n\tPTR: %s\n\tAddress of the pointed Value: %x\n\tValue of the whole String: %s\n\tValue of the first character of the String: %c\n", s, ptr,ptr,ptr,*ptr);
In my experience you should get segmentation fault when you try to use %s directive with *p.