overwriting character arrays in C

So, I've noticed that if I have code like this:


char userName[32];
scanf("%s", userName);
printf(" %s", userName);


When I run the program, when it comes time to type in my name, I've noticed that I can enter a name well over 32 characters, and the next statement will still print back the full 32+ character string, showing that, even though userName was declared to hold 32 characters or less, it still can hold more than that.

My instinct is to ask why C allows you to do this, but I'm going to try to stick to the relevant question here, which is -- is there a reason that I should refrain from letting C overwrite the character array like this? Does it matter if my user (not that I have a user, but for argument's sake) enters something over 32 characters, since the array will hold it anyways?

MacBook, Mac OS X (10.5.8)

Posted on Oct 10, 2009 2:58 AM

Reply
6 replies

Oct 10, 2009 5:20 AM in response to jpimbert

Yeah I know about formatting the number of characters like that and about the terminating null character and all that, but thank you for your post. I'm asking more about the way C will write past the number of characters that the array was declared to hold. Since the array can hold more characters than you declared it to reserve space for, why not just declare every character array to be only one character long, for example, since it will hold more than that anyways? In other words, what's the reason for reserving 32, for example, characters when declaring a character array if it will hold more than that anyways? Like I said in the last post with this code:


char userName[32];
printf("%s", "Enter your name: ");
scanf("%s", userName);


userName will hold as many characters as you type in here, even if it's more than 32. I'm always told in my books, though, to make sure you always declare a character array to reserve enough space for the maximum amount of characters you want your char array to hold (+1 for the null character), but why does this matter, since it will write past those 32 characters anyways?

Oct 10, 2009 2:35 PM in response to Tron55555

Tron55555 wrote:
My instinct is to ask why C allows you to do this


By all means, go with your instinct. It is a far more interesting question. One of the problems with C is that, to do it well, you have to go really in depth with details of how to do low-level computing tasks as opposed to how to implement the logic of your program. And yet, so much software, even today, is still written in C. How do programmers do it, you ask? The answer - not well.

is there a reason that I should refrain from letting C overwrite the character array like this? Does it matter if my user (not that I have a user, but for argument's sake) enters something over 32 characters, since the array will hold it anyways?


As M. Imbert has already said, the array won't hold it. You just got lucky, or unlucky.

One of the problems that many self-taught programmers encounter (and usually refuse to accept) is that lots of really bad code works. Or, at least it works in the limited test cases that they try. Then they get very defensive about their code because "it works" on Linux, Windows, or in some other venue.

What you have to do in C is be very nit picky about null terminators, allocation sizes, result codes, etc. It all gets very complex in a hurry. Because of these details, C is good for learning how to program. Just don't expect to be very productive at it.

Oct 10, 2009 5:19 PM in response to Tron55555

Analyze the following program and the output I've provided. Is it generating correct results?

#include <stdio.h>
#include <string.h>
main()
{
char a[4];
char b[32];
char c[4];
strcpy(a, "abc");
strcpy(c, "qrs");
strcpy(b, "123456789.123456789.123456789.12xyz");
printf("addr of a: %p contents of a: %s ",a,a);
printf("addr of b: %p contents of b: %s ",b,b);
printf("addr of c: %p contents of c: %s ",c,c);
}

Here are the results. Are they correct?

addr of a: 0xbfffee8c contents of a: xyz
addr of b: 0xbfffee6c contents of b: 123456789.123456789.123456789.12xyz
addr of c: 0xbfffee68 contents of c: qrs

Now extrapolate to your scanf() question.

char userName[32];
scanf("%s", userName);
printf(" %s", userName);

I will also point out that my a, b, c variables are on the stack. Just beyond 'a' is the return address to 'main'. If I overwrite 'b' far enough, I'll overwrite the return address for 'main' which means I might return to some random location. This would apply to any function's return address.

NOTE: overwriting another variable by exceeding the size of an array, is also known as "Buffer Overflow" and is commonly used in "Security Exploits". You overwrite a string that is not bounds checked, and trash the return address, cause the program to run exploit code, and thus causing a program to perform activities it was not intended to do.

Oct 11, 2009 3:49 AM in response to BobHarris

Okay -- thanks to you three for your answers. I actually don't think I have any more questions on the subject. I think the essence of what I was looking to hear is that, despite the fact that it worked (or seemed to work) with more than 32 characters, I still need to always be careful to make sure it stays within bounds. And Bob, your code was helpful in confirming this concept, so thank you for that. Much appreciated, as always.

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

overwriting character arrays in C

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.