Can a pointer to a string be used in a printf? - c

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.

Related

Difficult time understanding string pointers in C

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.

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.

Pointer to a string and the difference between assignment and dereferencing

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.

Assign pointer type to string type

I'm expecting a compile error , taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s. By adding an ampersand &, by right it should generate the address of the array and assign the memory address into %p, instead of giving the value of the string. Unless I dereference the pointer, but I don't dereference the pointer at all, I never put an asterisk * in front of my_pointer in printf.
#include <stdio.h>
int main()
{
char words[] = "Daddy\0Mommy\0Me\0";
char *my_pointer;
my_pointer = &words[0];
printf("%s \n", my_pointer);
return 0;
}
please look at this :
printf("%s \n", my_pointer);
My understanding is , *my_pointer (with asterisk *)should give me the value of the string.
But my_pointer (without asterisk) shouldn't give me the value of the string, but it should give me only the memory address,but when I run this code, I get the value of string eventhough I didn't put the asterisk * at the front. I hope I'm making myself clear this time.
Here:
printf("%s \n", my_pointer);
%s, expects a char* and since my_pointer is a char* which points to an array holding a NUL-terminated string, the printf has no problems and is perfectly valid. Relevant quote from the C11 standard (emphasis mine):
7.21.6.1 The fprintf function
[...]
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. 280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
[...]
IMO, You are being confused here:
taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s
First of all, %s, %p etc are conversion specifiers. They are used in some functions like printf, scanf etc.
Next, you are the one specifying the type of the pointers. So here:
my_pointer = &words[0];
&words[0] as well as my_pointer is of type char*. Assigning these two is therefore perfectly valid as both are of the same type.
The compiler is treating your code exactly as it is required to.
The %s format specifier tells printf() to expect a const char * as the corresponding argument. It then deems that pointer to be the address of the first element of an array of char and prints every char it finds until it encounters one with value zero ('\0').
Strictly speaking, the compiler is not even required to check that my_pointer is, or can be implicitly converted to, a const char *. However, most modern compilers (assuming the format string is supplied at compile time) do that.
In c, array name is also pointer to the first element, means in your case words and &words[0] when as a pointer, they have the same value.
And, you assign it to another pointer of the same type, so this is legal.
About string in c, it's just an array of chars ending with '\0', with its name pointer to the first char.

Behaviour of scanf() [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
confusion in scanf() with & operator
Why we need a & in scanf for inputting integer and why not for characters.
Do the & in scanf refers to merory location while getting input.
Eg:-
main()
{
int a;
char c;
scanf("%d",&a);
scanf("%c"c);
}
For each conversion specifier, scanf() expects the corresponding argument to be a pointer to the proper type: %d expects an argument of type int *, %f expects an argument of type double *, %c and %s both expect an argument of type char *, etc.
The difference between %c and %s is that the former tells scanf() to read a single character and store it in the location specified by the corresponding argument, while the latter tells scanf() to read multiple characters until it sees a 0-valued character and store all those characters in the buffer starting at the location specified by the argument.
You need to use the & operator on your arguments if they are not already of pointer type. For example:
int x;
int *px = some_valid_memory_location_such_as_&x;
char c;
char *pc = some_valid_memory_location_such_as_&c;
...
scanf("%d", &x); // x is not a pointer type, so we must use the & operator
scanf("%d", px); // px is a pointer type, so we don't need the & operator
scanf("%c", &c); // etc.
scanf("%c", pc); // etc.
Where things get confusing is reading strings of characters (using the %s conversion specifier):
char buf[SIZE];
scanf("%s", buf); // expression 'buf' *implicitly* converted to pointer type
Why don't we need the & operator in this case? It has to do with how C treats array expressions. When the compiler sees an expression of array type (such as buf in the scanf() call), it will implicitly convert the expression from type N-element array of T to pointer to T, and set its value to the address of the first element in the array. This value is not an lvalue -- it cannot be assigned to (so you can't write something like buf = foo). The only exceptions to this rule are when the array expression is an operand of either the sizeof or & operators, or if the array expression is a string literal being used to initialize another array:
char *p = "This is a test"; // string literal implicitly converted to char *,
// string *address* written to p
char a[] = "This is a test"; // string literal not implicitly converted,
// string *contents* copied to a
In short, the expression buf is implicitly converted from type char [SIZE] to char *, so we don't need to use the & operator, and in fact the type of the expression &buf would be pointer to SIZE-element array of char, or (*)[SIZE], which is not what scanf() expects for the %s conversion specifier.
The ampersand symbol is required in both cases. scanf requires pointers (you were probably thinking of char* or char[] - they are pointers themselves).
Scanf reads input to a memory address. a is the value held by a. &a is the location of a in memory.
In your code above, the c should be &c.
Because scanf() needs pointers, and &a is the pointer to an integer.
In your example, you need a comma and an ampersand in front of the c.
int main(void)
{
int a;
char c;
char s[21];
scanf("%d",&a);
scanf("%c", &c); // Fixed!
scanf("%20s", s);
printf("a = %d, c = %c, s = <<%s>>\n", a, c, s);
}
If you were reading a string, you would pass the string - a pointer to char - to scanf().
You need to provide scanf with pointer, that's why you have & in scanf("%d",&a);
. scanf("%c"c); will not work at all.
Your example is wrong. If you have a
char c;
then you need to add an & to the name when calling scanf:
scanf("%c", &c);
However, if your variable is already a pointer, for example because it is a char[] (which is a fancy syntax for pointers), you have to omit the &.
I like to think of the ampersand (&) as "address of". So you'd read &a as "address of a".
Also, I tried compiling this but it warned me on gcc:
Warning: format "%c" expects type 'char *', but argument 2 has type 'int'
Which is true, since a char is basically an int.

Resources