dan9duong7
dan9duong7

Reputation: 13

How could constant array in C changed

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

Answers (4)

David C. Rankin
David C. Rankin

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

bolov
bolov

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

user9522315
user9522315

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

Andrew Sun
Andrew Sun

Reputation: 4241

  1. 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.

  2. 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

Related Questions