sorry about the posting thing, i hadnt realized...
hope this is the correct way...
Now It's killing me! Why does it crash on the Fifth element!
why not first?! or after a lot?!
That's the way undefined behavior in C works. It might even not
crash at all, or it might crash only when your boss is looking,
or it might format your hard drive.
The C language defines how a compiled program should behave, and
it defines some boundaries your code may not cross. Usually there
are no checks neither at compile time nor run time that those
boundaries are not crossed. But after they are crossed absolutly
anything could happen according to the standard.
One of those boundaries is memory. The standard say you may
use memory you own, and you must not use memory you don't own.
In the real world with "normal" platforms (Unix, Windows, Mac
et cetera), undefined behavior usally leads to some pretty
predictable behavior, when you are familiar with the
implementation.
For example, when you start a program on a typical 32 bit unix
(or windows) platform that program (or process actually) has its
own 4 GB "virtual" address starting at 0x00000000 and ending at
0xFFFFFFFF. The operating system maps some of those virtual
addresses to physical memory, and some addresses are not mapped
at all. Several processes running simultaniously could have
a mapping for the same virtual address, but then it would map
to different physical locations. (All this is handled by the
operating system, and is usually nothing a programmer would have
to care about). This means that it is pretty hard for a C program
to write data into memory owned by another running process. So in
theory undefined behavior could lead to another unrelated process
to crash, that is quite unlikely to happen.
By the way, what does "crash" mean? In unix, sometimes a process
suddenly writes a message to stderr saying something like:
"segmentation fault", writes a file named "core" somewhere and
then disappears entirely from the face of earth. (in windows
a message dialog pops up instead, saying "access violation..."). Where
does that message come from? It is unlikely that are any statements
like fprintf(stderr, "segmentation fault\n"); in the programs
source code. The answer is that it was the operating system which
aborted the program and wrote the message (or showed the message
dialog). "Segmentation fault" usally means that the process tried
to read from or write to memory a virtual memory address that
either was not mapped to any physical address, or mapped to
an address which was protected from that kind of access (executable
code is usally read-only for example).
The memory for a running process could be organized like this:
+-----------------------------------+
| | 0xFFFFFFFF
| |
| |
| |
| Unmapped memory addresses |
| |
| |
| |
| |
+-----------------------------------+
| |
| |
| |
| |
| Mapped memory addresses |
| |
| |
| |
| |
| |
| |
| |
| |
+-----------------------------------+
| |
| |
| Unmapped memory addresses |
| |
| |
| | 0x00000000
+-----------------------------------+
A program trying to read or write to an unmapped memory address
invokes undefined behavior, and anything *could* happen, but
in reallity a pretty predictable "crash" is the result.
But the C language standard does not say: "You may not write
to unmapped addresses". It says that you may not write to memory
not "owned" or "allocated" by the program. All unmapped memory
is also not owned by the program, but also a large portion
of the mapped memory is not owned by the program. A read or
write operation to this memory is still undefined behavior, but
is much less likely to be caught by the operating system, so usually
the result is that nothing "unexpected" will happen at the very
momement of the read or write operation, but it is quite likely
that some data needed later gets destroyed, resulting in a "crash"
later (when the boss looks over your shoulder).
The following program invokes undefined behavior:
/* undef.c */
#include <stdio.h>
int main(void)
{
int i;
int array[2];
for (i = 0; i < 4; ++i) {
printf("i = %d\n", i);
array
= 0;
}
printf("The end!\n");
return 0;
}
It writes a zero to element 0-3 of 'array' which only has elements
0-1. The output from my system is (it could be something else on your):
% gcc undef.c -o undef
% ./undef
i = 0
i = 1
i = 2
i = 3
i = 1
i = 2
i = 3
i = 1
i = 2
i = 3
Oops its looping. The entire logic of my program changed as a result
of writing past the end of an array. In this case array[3] happened
to be the same thing as i.
Below is an example of how the mapped memory of a process might be
organized.
+-----------------------------------+
| |
| Program stack |
| (function return addresses, |
| local variables and |
| function arguments |
| |
+-----------------------------------+
| |
| |
| Unused |
| |
| |
+-----------------------------------+
| |
| Free store |
| (also known as "heap") |
| This is where the malloc family |
| of function gets its memory. |
| |
| |
+-----------------------------------+
| |
| Executable code |
| main(), printf()... |
| |
+-----------------------------------+
| |
| Initialized data |
| (globals, local static, |
| string literals...) |
| |
+-----------------------------------+
The C standard says nothing of how memory should be organized,
but the scheme above is very common. The order of the different
sections might change between platforms and operating systems,
and there might be some additional sections, but except for
DS9000 and similar platform the above is in priniple true.
The impact of this is that it is pretty easy to predict what will
happen when a program uses memory illegally:
Writing out of bounds of a global array will modify another
global variable. Writing data to a function pointer will immediatly
crash the program (os protection of read-only memory). Writing
out of bounds of a dynamically allocated array will either corrupt
the free store or change the value of another dynamically allocated
variable. And finally writing out of bounds of a local variable
will either change the value of another local variable or corrupt
the call stack.
The worst error (in the meaning most difficult to debug) of these
errors, according to my experience, is corrupting the free store.
The reason is that the system (malloc family of functions) stores
book-keeping data (like the size of allocated arrays, and location
of freed arrays) together with the dynamically allocated variables,
and corrupting such data might lead to a program crash much much
much later in the program execution, in a totally unrelated part
of the program.
Hope the above rambling was of some help for someone, and not
considered too off topic by the rest...
/Niklas Norrthon