开发者

Character Array in C

When we define a character array as 'char name[10]', this indicate that the array 'name' can hold a string of length ten character. But in the program shown below the array name can hold more than ten characters. How is this possible?

//print the name of a person.  
char name[10];  
scanf("%s",name);  
printf("%s",name);  

Here if I enter a开发者_Go百科 name even of length greater than ten character, there is no run time error and the program prints all the characters I have entered. There is a program termination if I enter the name of twenty or more characters.

Note: I am running the program on Ubuntu9.04 using a gcc compiler.


Because scanf doesn't know how long the array is. The variable "name" is not of type "array" but of type "pointer" (or "address"). It says, start writing here and keep writing until you're done. You may be lucky and have some other not-as-critical stuff on your stack that gets overwritten, but eventually, scanf will write and write and overwrite something fatal, and you'll get a Segmentation Fault. That's why you must always pass the size of arrays around.

It's akin to giving a blind person a pencil and saying "start writing here", without them being able to see where the end of the paper is. They will eventually write on the table and damage something. (Note: this is not a knock on the blind, this is just a metaphor.)

In the above case, I highly recommend using fgets() to grab a specific amount from stdin, and then sscanf() to pull whatever information from that line and put it into separate variables as needed. Scanf() and fscanf() are evil, I have never found a use for them that fgets()+sscanf() can't more safely solve.

char line[1024]; /* arbitrary size */
if( fgets( line, 1024, stdin ) != NULL )
{
  fprintf( stdout, "Got line: %s", line );
}

Or for things beyond strings:

# cat foo.c
  #include <stdio.h>
  int main( int argc, char **argv )
  {
    int i;
    char line[1024];
    while( fgets( line, 1024, stdin ) != NULL )
    {
      if( sscanf( line, "%d", &i ) == 1 )
      { /* 1 is the number of variables filled successfully */
        fprintf( stdout, "you typed a number: %d\n", i );
      }
    }
  }
# gcc foo.c -o foo
# ./foo
  bar
  2
  you typed a number: 2
  33
  you typed a number: 33
  <CTRL-D>


With an array of size 10 chars, to represent a string in C You can really only use 9 characters and the null terminated character. If you use more than 9 characters (+1 termination) then you'll have undefined behavior.

You are simply overwriting memory that you shouldn't be. What happens whether segfault, or working as you expect is as good as random.


scanf allows for a maximum width specifier, as in

scanf("%9s", name);

This will read up to 9 characters and add a terminating NUL character, for a total of 10 characters.

What happens if you don't limit the amount of characters scanf can read? Well, then your string ends up overwriting something else. In this case, I guess your buffer is on the stack, so you overwrite something on the stack. The stack holds local variables, return addresses (to the function that called this function), and function arguments. Now, a malicious user could fill that buffer with arbitrary code, and overwrite the return address with the address of that code (there are many variants of this attack). A malicious user could execute arbitrary code through that program.


Welcome to C world...

  • C does not perform array bounds checking;
  • the name of an array is nothing else than a pointer to the first element of the array;
  • scanf (as used in Mohit example program) does not handle destination buffer size limit;
  • with a wrong pointer value you can write anywhere in memory and you should expect unpredictable behaviour, segmentation fault if you are lucky.


C has no checks on array length. It will allow you to overflow an array.

In you case there happens to be writable memory after the array so you don't crash if you overflow by a small amount (although who knows that you are corrupting).

Try this code and see what happen when you put in more than 10 characters.

char name[10];
char name2[10];  
scanf("%s",name);  
printf("%s",name);  
printf("%s",name2); 

Also the name array can hold 9 characters, the 10th needs to be the terminating null zero '\0'


How is this possible?

The array is allocated on the stack. Following it there may be empty space or data that is of less than national-security importance (e.g., callee-saves registers that are not actually used in the caller). Eventually if the name you enter is long enough, you overwrite something important. Including, under some compilers, the return address!

Running the program under valgrind will detect an overrun error instantly.


You are exploiting undefined behaviour therefore anything can happen - program can crash or keep running normally or start doing something weird.


When you say char c[10] you allocate 10 bytes for that variable. However, your program might "own" subsequent bytes as well, that's why you may not get a segfault. But you will run in to so many other problems you wish you had got a segfault.


Your code invokes Undefined Behavior. Never use scanf() to read a string, use fgets() instead.

scanf() and gets() have the exact same problem with memory overrun. You can easily read in more characters than your char[] can hold.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜