Reputation: 13
I created a const array string
with 7 elements and a sentinel character at the end of array. But when I use scanf("%s", string)
and enter a new string with more than 7 elements, such as "10987654321
", this constant array is modified. How could that happen? I mean, this is the constant array; how could it be changed, and receive more than 7 elements that I declared in the head of my code? Can anybody explain for me?
#include<stdio.h>
int main(){
const char string[8] = "1234567";
printf("string initialize is: %s", string);
printf("\n\n");
printf("scanfing d\n");
scanf("%s", string);
printf("string now: %s\n", string);
return 0;
}
My output is:
string initialize is: 1234567
scanfing d
10987654321
string now: 10987654321
Upvotes: 0
Views: 776
Reputation: 84569
In a follow on to your comment and the difficulty you are having understand why you can write to the const
qualified array in your scanf
call, declaring the character array string
as const
protects you the programmer from changing the contents of string
by issuing a compiler warning (provided by the -Wformat
option). It does not make the array string
itself immutable. It will issue a notice (a warning) if you try and change the contents -- that you are attempting to write into a constant object. It does not change the storage itself to read-only nor change the data segment within which string
is stored to .rodata
.
If you then discard the warning and ignore what the compiler is telling you, then depending on the compiler you may very well succeed in changing the contents of string
, but you invoke Undefined Behavior doing so. See C11 Standard - 6.7.3 Type qualifiers(p6). Further, undefined behavior results again when you write beyond the bounds of your array.
For example, take your code:
#include <stdio.h>
int main (void) {
const char string[8] = "1234567";
printf ("string initialize is: %s, string\n\nscanfing d\n", string);
scanf ("%s", string);
printf ("string now: %s\n", string);
return 0;
}
When you attempt to compile this program with warnings properly enabled, e.g.
$ gcc -Wall -Wextra -o /tmp/bin/conststring conststring.c
the compiler will issue a warning similar to:
conststring.c: In function ‘main’:
conststring.c:8:5: warning: writing into constant object (argument 2) [-Wformat=]
scanf ("%s", string);
^
That spells it out "warning: writing into constant object". Don't do that.
(note: older versions of the VS compiler will not flag the warning even if full warnings are enable with /Wall
)
Further, assuming there were no const
qualifier, you would want to protect your array bounds by including a field-width modifier to the "%s"
format-specifier to limit the number of characters that could be read, e.g.
scanf ("%7s", string);
note: the field-width modifier cannot be a variable or named constant, it must be an actual numeric value making it one of the only times it is acceptable to use a magic number within your code.
So, in short, you have two primary problems (1) you make a promise to the compiler to only treat string
as constant and then turn around and break the promise; and (2) you write beyond the bounds of your array. Both invoke Undefined Behavior.
Upvotes: 1
Reputation: 75727
It is undefined behavior. The format specifier %s
is for char*
but you pass a const char*
(the array decays).
Undefined behavior means that the standard doesn't define any behavior for your program. It could print what you see, it could print the original string, it could print gibberish, it could crash or anything could happen.
Also please enable compiler warnings. This would have been caught:
warning: format specifies type 'char *' but the argument has type 'const char *' [-Wformat]
scanf("%s", string); ~~ ^~~~~~ %7s
Regarding writing more than you allocated. Considering the array was not const (mutable) then writing more that 7 characters to it would also be Undefined Behavior.
Upvotes: 1
Reputation:
This is undefined behavior because you should always treat variables declared with const
as immutable (non-modifiable).
Specific implementations may allow certain const variables to be changed, but in the code you've shown it's still UB and you should always avoid such code.
Upvotes: 4
Reputation: 4241
string
is allocated on the stack since it is const char[]
instead of const char *
. What happens is a char
array is allocated on the stack, and the string is copied into that array. If you used the const char *
form, most compilers will place the string into a read-only section in the binary, causing the program to crash when you actually attempt to write to it. On the stack, there is no such protection.
scanf
uses variadic arguments, meaning the compiler does not know that it will modify the array that you pass in (it might do it anyways, but this is not required by the C standard).
Upvotes: -1