Search code examples
ctr24731

C program stops working with scanf_s


I am fairly new at programming and I am having trouble with a piece of code. I am trying to input a word but when I run the program and enter the word it stops working.

This is the code:

    int main(void){
    char a[]= ""; 

    printf("Enter word:\n");
    scanf_s("%s", a);

    return 0;
}

I tried giving a[] a size of 20 and used %19s as another question suggested but that did not work either.

Edit 1. Changed char a[]= ""; to char a[20]= {0}; but it did not worked.

Edit 2. Added sizeof(a) and the code worked. Additionally, I removed the {0} but I don't know if that made a difference.

Final code:

int main(void){

    char a[20]; 

    printf("Enter word:\n");
    scanf_s("%19s", a, sizeof(a));

    return 0;

}

Solution

  • Diagnosis

    There are (at least) two problems in the code:

    1. You've not provided any useful space to store the string. (The original question defined: char a[] = "";, which — be it noted — is an array of length 1 though it can only hold a string of length 0.)

    2. You've not told scanf_s() how big the string is. It requires a length argument after the pointer to a character string.

    Microsoft's definition for scanf_s() specifies:

    Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size to be specified for all input parameters of type c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters is passed as an additional parameter immediately following the pointer to the buffer or variable. For example, if you are reading a string, the buffer size for that string is passed as follows:

    char s[10];
    scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9 
    

    The buffer size includes the terminating null. You can use a width specification field to ensure that the token that's read in will fit into the buffer. If no width specification field is used, and the token read in is too big to fit in the buffer, nothing is written to that buffer.

    Note

    The size parameter is of type unsigned, not size_t.

    The _countof() operator is a Microsoft extension. It is approximately equivalent to sizeof(s) / sizeof(s[0]), which in this case is the same as sizeof(s) since sizeof(char) == 1 by definition.

    Note that the size parameter is unsigned, not size_t as you would expect. This is one of the areas of difference between the Microsoft implementation of the TR 24731-1 functions and Annex K of ISO/IEC 9899:2011. The size specified in the standard is technically rsize_t, but that is defined as size_t with a restricted range (hence the r):

    The type is rsize_t which is the type size_t.

    but the footnote (not shown) refers to the definition of RSIZE_MAX.

    See also Do you use the TR 24731 'safe' functions?

    Fixing the code in the question

    The example in the quote from Microsoft largely shows how to fix your code. You need:

    int main(void)
    {
        char a[4096];
        
        printf("Enter word:\n");
        if (scanf_s("%s", a, (unsigned)sizeof(a)) != 1)  // Note cast!
            fprintf(stderr, "scanf_s() failed\n");
        else
            printf("scanf_s() read: <<%s>>\n", a);
        
        return 0;
    }
    

    Note that I checked the result of scanf_s() rather than just assuming it worked, and reported errors on standard error.