While answering this question I compiled the code on Ideone and got this error
implicit declaration of function ‘scanf_s’ [-Wimplicit-function-declaration]
Isn't stdio.h is the header for scanf_s?
scanf_s is Microsoft-specific. Header is stdio.h but not in GCC.
Used to Read formatted data from the standard input stream. These versions of scanf,scanf_s, _scanf_l, wscanf, _wscanf_l have security enhancements
Where as Ideone uses GCC because of this only you got undefined reference to scanf_s
Mostly You can found this function in windows based compilers like
Visual Studio 2008 and Microsoft .NET 2010
Here and Here You found Interesting info about scanf_s
int scanf_s(
const char *format [,
argument]...
);
According to the MSDN help:
The scanf_s function reads data from the standard input stream stdin and writes the data into the location given by argument. Each argument must be a pointer to a variable of a type that corresponds to a type specifier in format. If copying takes place between strings that overlap, the behavior is undefined.
Unlike scanf, scanf_s requires the buffer size to be specified for all input parameters of type c, C, s, S, or [. The buffer size is passed as an additional parameter immediately following the pointer to the buffer or variable. For example, if reading a string, the buffer size for that string is passed as follows:
char s[10];
scanf_s("%9s", s, 10);
The buffer size includes the terminating null. A width specification field may be used to ensure that the token read in will fit into the buffer. If no width specification field is used, and the token read is too big to fit in the buffer, nothing will be written to that buffer.
In the case of characters, one may read a single character as follows:
char c;
scanf_s("%c", &c, 1);
When reading multiple characters for non-null terminated strings, integers are used as the width specification and the buffer size.
char c[4];
scanf_s("%4c", &c, 4); // not null terminated
Related
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;
}
Diagnosis
There are (at least) two problems in the code:
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.)
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.
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.
In the various cases that a buffer is provided to the standard library's many string functions, is it guaranteed that the buffer will not be modified beyond the null terminator? For example:
char buffer[17] = "abcdefghijklmnop";
sscanf("123", "%16s", buffer);
Is buffer now required to equal "123\0efghijklmnop"?
Another example:
char buffer[10];
fgets(buffer, 10, fp);
If the read line is only 3 characters long, can one be certain that the 6th character is the same as before fgets was called?
The C99 draft standard does not explicitly state what should happen in those cases, but by considering multiple variations, you can show that it must work a certain way so that it meets the specification in all cases.
The standard says:
%s - Matches a sequence of non-white-space characters.252)
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence and a terminating null character, which will be added automatically.
Here's a pair of examples that show it must work the way you are proposing to meet the standard.
Example A:
char buffer[4] = "abcd";
char buffer2[10]; // Note the this could be placed at what would be buffer+4
sscanf("123 4", "%s %s", buffer, buffer2);
// Result is buffer = "123\0"
// buffer2 = "4\0"
Example B:
char buffer[17] = "abcdefghijklmnop";
char* buffer2 = &buffer[4];
sscanf("123 4", "%s %s", buffer, buffer2);
// Result is buffer = "123\04\0"
Note that the interface of sscanf doesn't provide enough information to really know that these were different. So, if Example B is to work properly, it must not mess with the bytes after the null character in Example A. This is because it must work in both cases according to this bit of spec.
So implicitly it must work as you stated due to the spec.
Similar arguments can be placed for other functions, but I think you can see the idea from this example.
NOTE:
Providing size limits in the format, such as "%16s", could change the behavior. By the specification, it would be functionally acceptable for sscanf to zero out a buffer to its limits before writing the data into the buffer. In practice, most implementations opt for performance, which means they leave the remainder alone.
When the intent of the specification is to do this sort of zeroing out, it is usually explicitly specified. strncpy is an example. If the length of the string is less than the maximum buffer length specified, it will fill the rest of the space with null characters. The fact that this same "string" function could return a non-terminated string as well makes this one of the most common functions for people to roll their own version.
As far as fgets, a similar situation could arise. The only gotcha is that the specification explicitly states that if nothing is read in, the buffer remains untouched. An acceptable functional implementation could sidestep this by checking to see if there is at least one byte to read before zeroing out the buffer.
Each individual byte in the buffer is an object. Unless some part of the function description of sscanf or fgets mentions modifying those bytes, or even implies their values may change e.g. by stating their values become unspecified, then the general rule applies: (emphasis mine)
6.2.4 Storage durations of objects
2 [...] An object exists, has a constant address, and retains its last-stored value throughout its lifetime. [...]
It's this same principle that guarantees that
#include <stdio.h>
int a = 1;
int main() {
printf ("%d\n", a);
printf ("%d\n", a);
}
attempts to print 1 twice. Even though a is global, printf can access global variables, and the description of printf doesn't mention not modifying a.
Neither the description of fgets nor that of sscanf mentions modifying buffers past the bytes that actually were supposed to be written (except in the case of a read error), so those bytes don't get modified.
The standard is somewhat ambiguous on this, but I think a reasonable reading of it is that the answer is: yes, it's not allowed to write more bytes to the buffer than it read+null. On the other hand, a stricter reading/interpretation of the text could conclude that the answer is no, there's no guarantee. Here's what a publicly avaialble draft says about fgets.
char *fgets(char * restrict s, int n, FILE * restrict stream);
The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.
There's a guarantee about how much it is supposed to read from the input, i.e. stop reading at newline or EOF and not read more than n-1 bytes. Although nothing is said explicitly about how much it's allowed to write to the buffer, the common knowledge is that fgets's n parameter is used to prevent buffer overflows. It's a little strange that the standard uses the ambiguous term read, which may not necessarily imply that gets can't write to the buffer more than n bytes, if you want to nitpick on the terminology it uses. But note that the same "read" terminology is used about both issues: the n-limit and the EOF/newline limit. So if you interpret the n-related "read" as a buffer-write limit, then [for consistency] you can/should interpret the other "read" the same way, i.e. not write more than what it read when string is shorter than the buffer.
On the other hand, if you distinguish between the uses of the phrase-verb "read into" (="write") and just "read", then you can't read the committee's text the same way. You are guaranteed that it won't "read into" (="write to") the array more than n bytes, but if the input string is terminated sooner by newline or EOF you're only guaranteed the rest (of the input) won't be "read", but whether that implies in won't be "read into" (="written to") the buffer is unclear under this stricter reading. The crucial issue is keyword is "into", which is elided, so the problem is whether the completion given by me in brackets in the following modified quote is the intended interpretation:
No additional characters are read [into the array] after a new-line character (which is retained) or after end-of-file.
Frankly a single postcondition stated as a formula (and would be pretty short in this case) would have been a lot more helpful than the verbiage I quoted...
I can't be bothered to try and analyze their writeup about the *scanf family, because I suspect it's going to be even more complicated given all the other things that happen in those functions; their writeup for fscanf is about five pages long... But I suspect a similar logic applies.
is it guaranteed that the buffer will not be modified beyond the null
terminator?
No, there's no guarantee.
Is buffer now required to equal "123\0efghijklmnop"?
Yes. But that's only because you've used correct parameters to your string related functions. Should you mess up buffer length, input modifiers to sscanf and such, then you program will compile. But it will most likely fail during runtime.
If the read line is only 3 characters long, can one be certain that the 6th character is the same as before fgets was called?
Yes. Once fgets() figures you have a 3 character input string it stores the input in the provided buffer, and it doesn't care about the reset of provided space at all.
Is buffer now required to equal "123\0efghijklmnop"?
Here buffer is just consists of 123 string guaranteed terminating at NUL.
Yes the memory allocated for array buffer will not get de-allocated, however you are making sure/restricting your string buffer can atmost only have 16 char elements which you can read into it at any point of time. Now depends whether you write just a single char or maximum what buffer can take.
For example:
char buffer[4096] = "abc";`
actually does something below,
memcpy(buffer, "abc", sizeof("abc"));
memset(&buffer[sizeof("abc")], 0, sizeof(buffer)-sizeof("abc"));
The standard insists that if any part of char array is initialized that is all it consists of at any moment until obeying its memory boundary.
There are no any guarantees from standard, which is why the functions sscanf and fgets are recommended to be used (with respect to the size of the buffer) as you show in your question (and using of fgets is considered preferable compared with gets).
However, some standard functions use null-terminator in their work, e.g. strlen (but I suppose you ask about string modification)
EDIT:
In your example
fgets(buffer, 10, fp);
untouching characters after 10-th is guaranteed (content and length of buffer will not be considered by fgets)
EDIT2:
Moreover, when using fgets keep in mind that '\n' will be stored in the buffers. e.g.
"123\n\0fghijklmnop"
instead of expected
"123\0efghijklmnop"
Depends on the function in use (and to a lesser degree its implementation). sscanf will start writing when it encounters its first non-whitespace character, and continue writing until its first whitespace character, where it will add a finishing 0 and return. But a function like strncpy (famously) zeroes out the rest of the buffer.
There is however nothing in the C standard which mandates how these functions behave.
This question already has answers here:
Reading a character with scanf_s
(3 answers)
Closed 3 years ago.
I'm trying to use scanf_s() to read in multiple values but every time I run the program, I get
Unhandled exception at 0x592AD6AC (msvcr120d.dll) in lab 2.exe: 0xC0000005: Access violation writing location 0x00000000.
in a popup window. How do I fix this?
float inTemp;
char inUnit;
char outUnit;
printf("Please enter the starting temperature with its units and the units\nyou would like to convert to (i.e. 74.5 F C): ");
scanf_s("%f %c %c", &inTemp, &inUnit, &outUnit); //takes in all user input (NOT WORKING)
You have not provided a length indicator. From MSDN:
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
Here is a link to that page.
If you really want to use (less portable) scanf_s, from the C11 standard (n1570), Annex K 3.5.3.2 p.4:
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.
You need to give the lengths of your char * arguments:
scanf_s("%f %c %c", &inTemp, &inUnit, 1, &outUnit, 1);
Alternatively, just use scanf:
scanf("%f %c %c", &inTemp, &inUnit, &outUnit);
And, as always, check the return values.
In general, as scanf is somtimes useful for little quick-and-dirty programmes, it’s of less use for productive software, because handling errors is hard. Use fgets and sscanf/strtod/strtol/… instead.
Is snprintf always null terminating the destination buffer?
In other words, is this sufficient:
char dst[10];
snprintf(dst, sizeof (dst), "blah %s", somestr);
or do you have to do like this, if somestr is long enough?
char dst[10];
somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);
I am interested both in what the standard says and what some popular libc might do which is not standard behavior.
As the other answers establish: It should:
snprintf ... Writes the results to a character string buffer. (...)
will be terminated with a null character, unless buf_size is zero.
So all you have to take care is that you don't pass an zero-size buffer to it, because (obviously) it cannot write a zero to "nowhere".
However, beware that Microsoft's library does not have a function called snprintf but instead historically only had a function called _snprintf (note leading underscore) which does not append a terminating null. Here's the docs (VS 2012, ~~ VS 2013):
http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
Return Value
Let len be the length of the formatted data string (not including the
terminating null). len and count are in bytes for _snprintf, wide
characters for _snwprintf.
If len < count, then len characters are stored in buffer, a
null-terminator is appended, and len is returned.
If len = count, then len characters are stored in buffer, no
null-terminator is appended, and len is returned.
If len > count, then count characters are stored in buffer, no
null-terminator is appended, and a negative value is returned.
(...)
Visual Studio 2015 (VC14) apparently introduced the conforming snprintf function, but the legacy one with the leading underscore and the non null-terminating behavior is still there:
The snprintf function truncates the output when len is greater
than or equal to count, by placing a null-terminator at
buffer[count-1]. (...)
For all functions other than snprintf, if len = count, len
characters are stored in buffer, no null-terminator is appended,
(...)
According to snprintf(3) manpage.
The functions snprintf() and vsnprintf() write at most size bytes (including the trailing null byte ('\0')) to str.
So, yes, no need to terminate if size >= 1.
According to the C standard, unless the buffer size is 0, vsnprintf() and snprintf() null terminates its output.
The snprintf() function shall be equivalent to sprintf(), with the addition of the n argument which states the size of the buffer referred to by s. If n is zero, nothing shall be written and s may be a null pointer. Otherwise, output bytes beyond the n-1st shall be discarded instead of being written to the array, and a null byte is written at the end of the bytes actually written into the array.
So, if you need to know how big a buffer to allocate, use a size of zero, and you can then use a null pointer as the destination. Note that I linked to the POSIX pages, but these explicitly say that there is not intended to be any divergence between Standard C and POSIX where they cover the same ground:
The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of POSIX.1-2008 defers to the ISO C standard.
Be wary of the Microsoft version of vsnprintf(). It definitely behaves differently from the standard C version when there is not enough space in the buffer (it returns -1 where the standard function returns the required length). It is not entirely clear that the Microsoft version null terminates its output under error conditions, whereas the standard C version does.
However, note that Microsoft has changed the rules (vsnprintf()) since this answer was originally written:
Beginning with the UCRT in Visual Studio 2015 and Windows 10, vsnprintf is no longer identical to _vsnprintf. The vsnprintf function conforms to the C99 standard; _vnsprintf is kept for backward compatibility with older Visual Studio code.
Similar comments apply to snprintf() and sprintf().
Note also the answers to Do you use the TR 24731 safe functions? (see MSDN for the Microsoft version of the vsprintf_s()) and the Mac solution for the safe alternatives to unsafe C standard library functions?
Some older versions of SunOS did weird things with snprintf and might have not NUL-terminated the output and had return values that didn't match what everyone else was doing, but anything that has been released in the past 10 years have been doing what C99 says.
The ambiguity starts from the C Standard itself. Both C99 and C11 have identical description of snprintf function. Here is the description from C99:
7.19.6.5 The snprintf function
Synopsis
1 #include <stdio.h>
int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
Description
2 The snprintf function is equivalent to fprintf, except that the output is written into an array (specified by argument s) rather than to a stream. If n is zero, nothing is written, and s may be a null pointer. Otherwise, output characters beyond the n-1st are
discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array. If copying takes place between objects that overlap, the behavior is undefined.
Returns
3 The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.
On the one hand the sentence
Otherwise, output characters beyond the n-1st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array
says that
if (the s points to a 3-character-long array, and) n is 3, then 2 characters will be written, and the characters beyond the 2nd one are discarded; then the null character is written after those 2 (and the null character will be the 3rd character written).
And this I believe answers the original question.
THE ANSWER:
If copying takes place between objects that overlap, the behavior is undefined.
If n is 0 then nothing is written to the output
otherwise, if no encoding errors encountered, the output is ALWAYS null-terminated (regardless of whether the output fits in the output array or not; if not then some characters are discarded such that the output array is never overflown),
otherwise (if encoding errors are encountered) the output can stay non-null-terminated.
On the other hand
The last sentence
Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n
gives ambiguity (or my English is not good enough). I can interpret this sentence in at least two ways:
1. The output is null-terminated if and only if the returned value is nonnegative and less than n (which means that if the returned value is not less than n, i.e. the output (including the terminating null character) does not fit in the array, then the output is not null-terminated).
2. The output is complete (no characters have been discarded) if and only if the returned value is nonnegative and less than n.
I believe that the interpretation 1 above contradicts THE ANSWER, causes misunderstanding and lengthy discussions. That is why the last sentence describing the snprintf function needs a change in order to remove any ambiguity (which gives grounds for writing a Proposal to the C language Standard).
The example of non-ambiguous wording I believe can be taken from http://en.cppreference.com/w/c/io/fprintf (see 4)), thanks to #"Martin Ba" for the link.
See also the question "snprintf: Are there any C Standard Proposals/plans to change the description of this func?".
Is a NULL pointer allowed as the string to store result in in a call to sscanf?
I don't find anything about it in any documentation but it seems to be working fine. Same thing with scanf.
Example:
int main(int arc, char* argv[])
{
char* s = NULL;
sscanf("Privjet mir!", "%s", s);
printf("s: %s\n", s);
return 0;
}
Output: s: (null)
No:
Matches a sequence of non-white-space
characters; the next pointer must be a
pointer to character array that is
long enough to hold the input sequence
and the terminating null character
('\0'), which is added automatically.
The input string stops at white space
or at the maximum field width,
whichever occurs first.
(http://linux.die.net/man/3/sscanf)
As is mentioned by the other answers NULL is not valid to pass to sscanf as an additional argument.
http://www.cplusplus.com/reference/cstdio/sscanf says of additional arguments:
Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.
For the %s specifier these extracted characters are:
Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
So when the "non-whitespace characters" and "terminating null character" is stored, there will be a segfault. Which is exactly what Visual Studio will yield (you can test that this fails at http://webcompiler.cloudapp.net/):
Now as far as non-Visual Studio compilers, libc's extraction code for the %s specifier: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 has the leading comment: /* We might have to handle the allocation ourselves */ this is because:
The GNU C library supported the dynamic allocation conversion specifier (as a nonstandard extension) via the a character. This feature seems to be present at least as far back as glibc 2.0.
Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier.
[Source]
So because libc extracts to a buffer constructed internally to sscanf and subsequently checks that the buffer parameter has no flags set before assigning it, it will never write characters to a NULL buffer parameter.
I can't stress enough that this is non-standard, and is not guaranteed to be preserved even between minor library updates. A far better way to do this is to use the * sub-specifier which:
Indicates that the data is to be read from the stream but ignored (i.e. it is not stored in the location pointed by an argument).
[Source]
This could be accomplished like this for example:
s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);
Obviously the true-branch of the ternary is a no-op, but I've included it with the expectation that other data was expected to be read from the string.
The manpage says that, when using %s, the argument must be a pointer with enough space for the string and \0. So my guess would be that the behaviour in your case is undefined. It may work, it may also crash or corrupt memory and cause issues later.
No, this is not allowed.
sscanf %s expects a char* pointing to a sufficient large buffer, printf %s wants a nul char* buffer. Anything else results in undefined behavior. (And that means some implementations might detect and handle a null pointer in a certain way, other implementations might not)
I didn't find anything in the standard explicitly concerning NULL and *printf/*scanf.
I suppose that this is undefined behavior1, since it counts as passing an argument that is not coherent with the format specifier (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s means that a you're going to pass a pointer to the first element of a character array (large enough for the acquired string for *scanf, containing a NUL-terminated string for *printf) - and passing NULL doesn't satisfy this requirement.
1. In this case UB shows as "just ignoring the acquisition" and "printing (null)", on other platforms it may result in planes falling down the sky or the usual nasal demons.
Allocate the memory to s . Assign s to character array. Then run the program.
Following will work.
int main(int arc, char* argv[])
{
char s[100];
sscanf("Privjet mir!", "%[^\t]s", s);
printf("s: %s\n", s);
return 0;
}