Behaviour of scanf() [duplicate] - c

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.

Related

Dereferencing char pointer returns int ? why? [duplicate]

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.

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.

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

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.

scanf() (C Language ) confused me

When do I need to insert/don't insert & for scanf() in C? Thank you.
int main()
{
char s1[81], s2[81], s3[81];
scanf("%s%s%s", s1, s2, s3);
// If replace scanf() with the expression below, it works too.
// scanf("%s%s%s", &s1, &s2, &s3);
printf("\ns1 = %s\ns2 = %s\ns3 = %s", s1, s2, s3);
return 0;
}
//programming is fun
//
//s1 = programming
//s2 = is
//s3 = fun
scanf puts the scanned values in the address pointed by it's arguments. The & is the address operator, and it's used to take the address of a variable.
But, you are using arrays, and arrays are downgrade to pointers when used as functions arguments. So, you don't need to use the & operator in the case of arrays.
Example:
char s[81];
int n;
int* nptr;
//Initialize nptr to some meaningful value
scanf("%s %d %d",s,&n,nptr);
In this case, we need to use the & operator to get the address were n is kept. We don't need to use it with nptr, because it is already a pointer to someplace in the memory, neither with s, because an array gets downgrade to a pointer when it's passed to a function.
The arguments after the format specifier must be pointers. When an array name is passed to a function, the location of the initial element is passed, so you don't need to use the & at all in your example. You could do this though (from K&R):
int day, year;
char monthname[20];
scanf("%d %s %d", &day, monthname, &year);
Since day and year are int, you must use the & to get the address of those variables. Since monthname is an array, no & is required.
In C, when you are dealing with arrays:
int c_array[24];
c_array == &c_array == &c_array[0]
Yeah, its funny - they look the same (the difference is in the types). Read this.
From the comp.lang.c FAQ: I thought you always needed an & on each variable passed to scanf.
I highly recommend reading the rest of the comp.lang.c FAQ.
s1 returns the address of the first element of the array, while &s1 returns the address of the array itself. The address of the first element and the address of the array itself are identical, hence why both representations work.
Just a guess, but I'd assume it's because s1, s2, and s3 are arrays.
If a is an array, both a and &a result in a pointer in this context:
a does due to the array decaying to a pointer (C99, §6.3.2.1/3):
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
... emphasis added
&a does as a result of the & operator - it returns a pointer to the object.
Scanf accepts variable number of parameters. first argument of scanf is format and after that n addresses where values to be stored while n is the number of format specified in format string. since you are using array, to store values you have to provide base address of the array.
//If int
int i;
scanf("%d",&i); // store int value at address &i
float f;
scanf("%f",&f); //store float value at address &f
int a[10];
scanf("%s",a); //store string or array value at a
if using a in last line confuses you, you can try the same thing with address of first element which is &a[0].
Hope it helps,
GG
Generally, you would use scanf the way you do in your uncommented line. The way C arrays work, is the name of arrays like s1, s2, and s3 is actually the address of the first element of the array. For any primitives though, you would have to use the &variable syntax. For example:
float f;
scanf("%f", &f);

Resources