String input using C scanf_s
Solution 1
From the specification of fscanf_s()
in Annex K.3.5.3.2 of the ISO/IEC 9899:2011 standard:
The
fscanf_s
function is equivalent tofscanf
except that thec
,s
, and[
conversion specifiers apply to a pair of arguments (unless assignment suppression is indicated by a*
). The first of these arguments is the same as forfscanf
. That argument is immediately followed in the argument list by the second argument, which has typersize_t
and gives the number of elements in the array pointed to by the first argument of the pair. If the first argument points to a scalar object, it is considered to be an array of one element.
and:
The
scanf_s
function is equivalent tofscanf_s
with the argumentstdin
interposed before the arguments toscanf_s
.
MSDN says similar things (scanf_s()
and fscanf_s()
).
Your code doesn't provide the length argument, so some other number is used. It isn't determinate what value it finds, so you get eccentric behaviour from the code. You need something more like this, where the newline helps ensure that the output is actually seen.
char name[64];
if (scanf_s("%s", name, sizeof(name)) == 1)
printf("Your name is %s\n", name);
Solution 2
I used this very often in my university classes so this should work fine in Visual Studio (tested in VS2013):
char name[64]; // the null-terminated string to be read
scanf_s("%63s", name, 64);
// 63 = the max number of symbols EXCLUDING '\0'
// 64 = the size of the string; you can also use _countof(name) instead of that number
// calling scanf_s() that way will read up to 63 symbols (even if you write more) from the console and it will automatically set name[63] = '\0'
// if the number of the actually read symbols is < 63 then '\0' will be stored in the next free position in the string
// Please note that unlike gets(), scanf() stops reading when it reaches ' ' (interval, spacebar key) not just newline terminator (the enter key)
// Also consider calling "fflush(stdin);" before the (eventual) next scanf()
Ref: https://msdn.microsoft.com/en-us/library/w40768et.aspx
user3587529
Updated on July 09, 2022Comments
-
user3587529 almost 2 years
I've been trying to look for answer myself, but I can't find one. I want to insert a part of the programming that reads in a string like "Hello" and stores and can display it when I want, so that
printf("%s", blah);
producesHello
.Here's the code part that's giving me trouble
char name[64]; scanf_s("%s", name); printf("Your name is %s", name);
I know that
printf
isn't the problem; the program crashes after something is input after a prompt. Please help? -
someone_ smiley about 10 yearsisn't it : scanf("%s", name); (no '&')?
-
sarath about 10 years'&' is not required here. The array name itself will give the address of the array.
-
dmckee --- ex-moderator kitten about 10 yearsThe
&
on&name
does no harm, but is not needed. Leave it off because you understand the relationship between arrays and pointers. If you don't understand that relationship go read about it and then leave the extra&
off. -
wilson about 10 yearsI changed it. Sorry, just a habit.
-
user3587529 about 10 yearsStill didn't work, it doesn't crash anymore, but the printf won't show the result.
-
user3587529 about 10 yearsFinally found the comment, still doesn't work. I used yours as a test run and the command screen just shows: Enter your name: Your name isPress any key to close
-
M-N about 10 yearsI tried this and it worked, #include <stdio.h> int main(void) { char name[64]; scanf ("%63s", name); printf("Your name is %s", name); return 0; }
-
wilson about 10 yearsThe first line is prompting you for input, after you type in a name the program will display it back to you.
-
user3587529 about 10 yearsI'm using Visual Studio and it won't let me use scanf, just scanf_s, but even with the buffer, it won't work, just skips the %s in the printf afterwards.
-
M-N about 10 yearsyou started a visual c++ project?
-
user3587529 about 10 yearsYes, I'm assuming that that's the problem... but what specifically?
-
M-N about 10 yearsgo to Project properties->Configuration Properties->C/C++->Preprocessor->Preprocessor Definitions click on edit and add _CRT_SECURE_NO_WARNINGS click ok, apply the settings and run the project
-
M.M about 10 years@dmckee,
name
is correct and&name
is wrong, however on common implementations both of those have the same representation, so it usually works. The%s
specifier expects achar *
. -
dmckee --- ex-moderator kitten about 10 years@MattMcNabb I agree that the correct for is without, but I don't think that it is by chance that it works the wrong way. I can't quote chapter and verse, but I think this is required:
&name
returns a pointer to achar
array not a pointer tochar
, but scanf is variadic so all pointers are converted tovoid*
, and a char array must be stored in a way that allows pointer indexing to work on it, so the&name
form must work even though it is incorrect. Or something like that. -
dmckee --- ex-moderator kitten about 10 yearsHmmm ... may be wrong about the pointer conversion. In which case a hypothetical compiler that stores pointers to arrays differently than other pointers could conceivably show different behavior.
-
Spikatrix about 9 yearsShouldn't the third argument of
scanf_s
be cast to(unsigned int)
assizeof
returns a value of typesize_t
? -
Jonathan Leffler about 9 years@CoolGuy: If you're going to cast it, it should be cast to
rsize_t
(see the quote in the answer), but K.3.3 Common definitions<stddef.h>
says (in its entirety): The header <stddef.h> defines a type.The type isrsize_t
which is the typesize_t
. and references footnote 385, which says: See the description of theRSIZE_MAX
macro in<stdint.h>
. The discussion ofRSIZE_MAX
is considerably more extensive, but the intent is that it should usually be smaller thanSIZE_MAX
, withSIZE_MAX >> 1
being a suggested size. -
Jonathan Leffler about 9 years@dmckee: The notation
&name
generates achar (*)[64]
in the context of the question (char name[64];
). The%s
format expects achar *
, and simply referencingname
yields achar *
. As you can see, the two types are quite radically different. The unfortunate curiosity is that the value of&name
viewed as avoid *
is the same as the value ofname
viewed as avoid *
. This allowsscanf("%63s", &name)
to 'work', but doesn't stop it being incorrect. -
Jonathan Leffler about 9 years@dmckee: Also note that the compiler does not do any type conversions on the pointers passed to
scanf()
— only integer types shorter thanint
or floating type shorter thandouble
are subject to default argument promotion when passed to variadic functions such asscanf()
, and sincescanf()
only takes pointers (unlikescanf_s()
which also takes some integers), there is no default argument promotion in valid calls toscanf()
. -
Dev-iL about 7 yearsWelcome to Stack Overflow! While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. It also doesn't hurt to mention why this answer is more appropriate than others.
-
Aashishkebab about 5 yearsAh, yes. A code snippet with no context and doesn't answer the question. Brilliant.