7

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); produces Hello.

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?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user3587529
  • 81
  • 1
  • 1
  • 3

7 Answers7

7

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 to fscanf except that the c, 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 for fscanf. That argument is immediately followed in the argument list by the second argument, which has type rsize_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 to fscanf_s with the argument stdin interposed before the arguments to scanf_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);
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Shouldn't the third argument of `scanf_s` be cast to `(unsigned int)` as `sizeof` returns a value of type `size_t`? – Spikatrix Feb 20 '15 at 15:20
  • @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 ``** says (in its entirety): _The header defines a type.The type is `rsize_t` which is the type `size_t`._ and references footnote 385, which says: _See the description of the `RSIZE_MAX` macro in ``._ The discussion of `RSIZE_MAX` is considerably more extensive, but the intent is that it should usually be smaller than `SIZE_MAX`, with `SIZE_MAX >> 1` being a suggested size. – Jonathan Leffler Feb 20 '15 at 15:29
5

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

NoobBG
  • 51
  • 1
  • 1
0

The scanf_s function is equivalent to scanf except that %c, %s, and %[ conversion specifiers each expect two arguments (the usual pointer and a value of type rsize_t indicating the size of the receiving array, which may be 1 when reading with a %c into a single char)

Your code doesn't provide the size of receiving array, also the variable name is a pointer pointing to the first character of the array, so it contains the address of name[0]. Therefore your first argument name in scanf_s is correct because name is a pointer, also note that, for the second argument you can't insert the size of a pointer like sizeof(name) because it is always same. You need to specify the size of your char array (name[64]), so for the second argument you should insert sizeof(name[64]) or 64*sizeof(char).

You can correct your code as follows:

char name[64];
if (scanf_s("%s", name, sizeof(name[64])) == 1)
    printf("Your name is %s\n", name);
Nick
  • 1
  • 1
0

Here is a part of code that works for me fine:

char name[64];
scanf_s("%63s", name,(unsigned)_countof(name));
printf("Your name is %s", name);

For more information here is a link: https://learn.microsoft.com/de-de/cpp/c-runtime-library/reference/scanf-s-scanf-s-l-wscanf-s-wscanf-s-l?view=msvc-170

Best Regards

-1

you should do this : scanf ("%63s", name);

Update:

The below code worked for me:

#include <stdio.h> 
int main(void) { 
    char name[64]; 
    scanf ("%63s", name); 
    printf("Your name is %s", name); 
    return 0; 
}

if you are using visual studio, go 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 again.

Note: this is only good if you are doing your homework or something like that and it's not recommended for production.

M-N
  • 300
  • 2
  • 14
  • Still didn't work, it doesn't crash anymore, but the printf won't show the result. – user3587529 Apr 30 '14 at 02:45
  • I tried this and it worked, #include int main(void) { char name[64]; scanf ("%63s", name); printf("Your name is %s", name); return 0; } – M-N Apr 30 '14 at 02:49
  • I'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. – user3587529 Apr 30 '14 at 02:56
  • you started a visual c++ project? – M-N Apr 30 '14 at 03:00
  • Yes, I'm assuming that that's the problem... but what specifically? – user3587529 Apr 30 '14 at 03:09
  • 1
    go 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-N Apr 30 '14 at 03:18
-1
    #include<stdio.h>

    int main()
    {
      char name[64];

      printf("Enter your name: ");
      scanf("%s", name);
      printf("Your name is %s\n", name);

     return 0;
    }
M.M
  • 138,810
  • 21
  • 208
  • 365
wilson
  • 19
  • 2
  • 2
    isn't it : scanf("%s", name); (no '&')? – someone_ smiley Apr 30 '14 at 02:31
  • 1
    '&' is not required here. The array name itself will give the address of the array. – sarath Apr 30 '14 at 02:35
  • 1
    The `&` 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. – dmckee --- ex-moderator kitten Apr 30 '14 at 02:36
  • I changed it. Sorry, just a habit. – wilson Apr 30 '14 at 02:37
  • Finally 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 – user3587529 Apr 30 '14 at 02:46
  • The first line is prompting you for input, after you type in a name the program will display it back to you. – wilson Apr 30 '14 at 02:51
  • @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 a `char *`. – M.M Apr 30 '14 at 03:46
  • @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 a `char` array not a pointer to `char`, but scanf is variadic so all pointers are converted to `void*`, 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 Apr 30 '14 at 04:16
  • 2
    Hmmm ... 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. – dmckee --- ex-moderator kitten Apr 30 '14 at 04:21
  • 1
    @dmckee: The notation `&name` generates a `char (*)[64]` in the context of the question (`char name[64];`). The `%s` format expects a `char *`, and simply referencing `name` yields a `char *`. As you can see, the two types are quite radically different. The unfortunate curiosity is that the value of `&name` viewed as a `void *` is the same as the value of `name` viewed as a `void *`. This allows `scanf("%63s", &name)` to 'work', but doesn't stop it being incorrect. – Jonathan Leffler Feb 20 '15 at 15:48
  • @dmckee: Also note that the compiler does not do any type conversions on the pointers passed to `scanf()` — only integer types shorter than `int` or floating type shorter than `double` are subject to _default argument promotion_ when passed to variadic functions such as `scanf()`, and since `scanf()` only takes pointers (unlike `scanf_s()` which also takes some integers), there is no default argument promotion in valid calls to `scanf()`. – Jonathan Leffler Feb 20 '15 at 15:49
-1
#include<stdio.h>

int main()
{
  char name[64];
  printf("Enter your name: ");
  gets(name);
  printf("Your name is %s\n", name);
 return 0;
}
Dev-iL
  • 23,742
  • 7
  • 57
  • 99
  • Welcome to Stack Overflow! While this code may answer the question, providing additional [context](https://meta.stackexchange.com/q/114762) 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. – Dev-iL Apr 06 '17 at 07:07
  • Ah, yes. A code snippet with no context and doesn't answer the question. Brilliant. – Aashishkebab Apr 16 '19 at 17:48