-2

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;

}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
CBeginner
  • 23
  • 3

2 Answers2

3

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.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1+ as mostly, however allow me this question: Do you do this as meditation exercise ... ;-) – alk May 03 '15 at 17:31
  • Thanks. I tried the example and the program worked. Although, I will need to study it because I don't understand most of it. – CBeginner May 03 '15 at 17:35
  • Most of it is the same as what you had. There's one extra argument in the call to `scanf_s()` — that's the crucial fix for your code. The `*scanf*()` functions return the number of successful conversions, or EOF on error. In this case, it is slightly pedantic, but it is good practice to check every input operation for success. If you've not come across `fprintf()` and `stderr`, then you can think of `fprintf(stderr, …)` as "a variant of `printf()` used for writing error messages". `fprintf()` can be used to write to any open file stream, and there are other ways of writing to `stderr` too. – Jonathan Leffler May 03 '15 at 17:41
  • 2
    @alk: I do this more as a way of avoiding doing all the other things I should be doing instead. – Jonathan Leffler May 03 '15 at 17:43
  • @JonathanLeffler: :-)) ... - so this answer definitly proves your are human! Cheers ... ;-) – alk May 03 '15 at 17:46
2

Using

char a[]="";

Creates an array big enough for a single byte. You have to allocate enough space, e.g. like this:

char a[20] = {0}; // Can hold a string length 19 + \0 termination

Using your method, you would get an overflow as the scanf_s will write more in the memory than you allocated, resulting in a segmentation fault.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Nidhoegger
  • 4,973
  • 4
  • 36
  • 81
  • I just wanted to point him to the right direction. With a size of 20 it should work for strings length 19. – Nidhoegger May 03 '15 at 17:08
  • 1
    The array is 1 byte long (it contains a `'\0'`); there are no zero-sized objects in C. – Jonathan Leffler May 03 '15 at 17:11
  • I've fixed the original thinko of asserting that `char a[] = "";` defines a zero-size array. It doesn't; it specifies an array of size 1. There are no zero size objects in C. This does not address the whole problem, though. The `scanf_s()` function requires the length of the target character array as an explicit extra argument to the function appearing immediately after the pointer argument. – Jonathan Leffler May 03 '15 at 17:36