2

My code:

#include <stdio.h>
int main() {
    char words[30];

    printf("Please typing text under 30 text!:");
    scanf_s("%s", words);

    printf("text: %s \n", words);

    return 0;
}

The error I get:

Missing integer argument to 'scanf_s' that corresponds to coversion specifier '2', 'scanf_s' not enough arguments passed for format string

wohlstad
  • 12,661
  • 10
  • 26
  • 39
Yooni
  • 41
  • 5
  • Thanks for removing the [tag:c++] tag. This is C, *not* C++; these are different languages. – Marcus Müller Dec 22 '22 at 14:29
  • 4
    Why are you using `scanf_s` if you're not passing in the length? – interjay Dec 22 '22 at 14:30
  • try `scanf_s("%s", words, sizeof(words));` – Alan Birtles Dec 22 '22 at 14:31
  • 3
    The whole point of (non-standard, Microsoft specific) `scanf_s` is to ensure that no buffer overflow is possible, by passing the maximum size of the target string (which can also be achieved using more standard ways) – chrslg Dec 22 '22 at 14:35
  • @chrslg its been in the c standard since 2011 https://en.cppreference.com/w/c/io/fscanf – Alan Birtles Dec 22 '22 at 14:37
  • 2
    @AlanBirtles First, [Annex K is **optional**](https://port70.net/~nsz/c/c11/n1570.html#K.2p1). Second, the [Microsoft implementation is in no standard in the known universe](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm#impementations): "Microsoft Visual Studio implements an early version of the APIs. However, the implementation is incomplete and conforms neither to C11 nor to the original TR 24731-1. ... As a result of the numerous deviations from the specification the Microsoft implementation cannot be considered conforming or portable." – Andrew Henle Dec 22 '22 at 14:43
  • 2
    @chrslg And here I thought the whole point of the Microsoft implementation was to provide a vendor-specific, non-portable implementation pushed by misleading-at-best-to-downright-false claims that C standard functions are "deprecated". – Andrew Henle Dec 22 '22 at 14:46
  • 1
    @AndrewHenle I think your comment was addressed to AlanBirtles, not me (I am the one that said it is not standard. I don't need convicing about Microsoft strategy to deem "unsafe" standard function and try to convince people that their home made version are the new standard. As we have just seen, apparently, it works). – chrslg Dec 22 '22 at 14:50
  • 1
    Plus, anyway, I can see that we are in 2022 (going on 2023), and none of my recent machine understand what `scanf_s` is. So, I'd say that either I use only very obsolete compiler, more than a decade late on so called standard (is `cppreference` was a reference, which it is not), or that "standard" is not really standard. So, in short, no, `scanf_s` is neither standard, nor needed. – chrslg Dec 22 '22 at 14:52
  • 1
    @chrslg My first comment was definitely not directed at you (hence the @AlanBirtles tag...). My second comment was, though. Every time I see the misleading/false MSVC "warnings" about "deprecated" standard C functions like `fopen()` it irks me. FWIW, read the entire critique at [**Field Experience With Annex K — Bounds Checking Interfaces**](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm) and the follow-on at [**Updated Field Experience With Annex K — Bounds Checking Interfaces**](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1969.htm) – Andrew Henle Dec 22 '22 at 15:10
  • 2
    (cont) "A widespread fallacy originated by Microsoft's deprecation of the standard functions [DEPR] in an effort to increase the adoption of the APIs is that every call to the standard functions is necessarily unsafe and should be replaced by one to the "safer" API. ..." – Andrew Henle Dec 22 '22 at 15:11
  • 1
    @AndrewHenle Ok. But I already know this quote, I often quote it myself, and couldn't agree more. So I am a little, well not offended, but, let's say surprised (:D), to have said something that could trigger such this quote at me. Was it because I said "the whole point of `scanf_s`..." (while saying "non-standard" twice in the same sentence)? Because it was to be understood as "why would one stoop to use non-standard misleading unnecessary Microsoft `scanf_s` if it is not at least to pass it the maximum size?" :D. Never mind, the point is I agree to all your points. – chrslg Dec 22 '22 at 15:22
  • 1
    @chrslg It was to back up your claim with actual documentation on a question that's relevant. The detail was also directed at all readers of this question. – Andrew Henle Dec 22 '22 at 15:29

3 Answers3

2

Consider using fgets instead if you're simply reading everything into a string buffer. It's simpler and more portable:

char buffer[31]; // 1 extra for the zero terminator

printf("Please enter text with less than %zu characters\n", sizeof(buffer) - 1);

if (!fgets(buffer, (int)sizeof(buffer), stdin)) {
  puts("Failed to read input");
} else {
  // use input
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • 2
    And `fgets()` is [certainly less perverse than any version of `scanf()`](https://stackoverflow.com/questions/2430303/disadvantages-of-scanf). – Andrew Henle Dec 22 '22 at 15:18
1

As you can see in the scanf_s documentation:

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)

I.e. for each argument you want scanf_s to parse, you need to pass its size.

Also scanf family return the number of arguments parsed, and you should check it to find out if it actually succeeded.

In your case change the scanf_s line to:

int n = scanf_s("%s", words, sizeof(words));
if (n != 1)
{
    // handle error
}

Note that sizeof(words) works here because it is an array allocated on the stack. If you allocate it as a pointer with malloc family you'll need to pass the right size (because then sizeof will return the size of the pointer itself).

wohlstad
  • 12,661
  • 10
  • 26
  • 39
0

Try this code:

#include <stdio.h>

    int main() {
      char words[30];
    
      printf("Please typing text under 30 text!:");
      scanf_s("%s", words,30);
    
      printf("text: %s \n", words);
    
      return 0;
    }

Also, you could put sizeof(words) instead of 30 as someone suggested (note that this is only possible if you are working with static memory).

If you are using scanf_s, I think you want to ensure to read n symbols. Someone already suggested you to use fgets. Another possible solution is to use memcpy (you will read the exact bytes):

#include <stdio.h>

    int main() {
      char words[30];
      char words2[30];

    
      printf("Please typing text under 30 text!:");
      scanf("%s", words);
      memcpy(words2,words,sizeof(char)*30);
      words2[sizeof(char)*30]='\0';
      printf("text: %s \n", words2);
    
      return 0;
    }
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
sacacorchos
  • 163
  • 9
  • Quite dangerous to use `sizeof(words)`. I mean, it would work in the case of an array. But if `words` was the result of `words=malloc(30)`, then `sizeof(words)` wouldn't be `30`. On another hand, if you use a static `30` value, it is even harder to argue why `scanf_s` is needed, since `scanf("%29s", words)` would do. – chrslg Dec 22 '22 at 14:57
  • You are right, in the case of dynamic memory, sizeof(words) would be 8. I think that 30 is okay as the op can see that it is the same value as the size of the string to ensure that no more than 30 characters will be read. – sacacorchos Dec 22 '22 at 15:21