As Epo says, a segmentation fault results from attempting to access memory that the system doesn't allow to be accessed. In practice, each process is allocated memory in segments, and each segment has different attributes (eg read-only data, read-write, executable, etc). An attempt to do something to memory at odds with attributes of the segment it is in (eg attempting to modify read-only data) results in a segmentation fault.
The causes aren't only related to falling off the end of arrays. Segmentation faults can also result from pointer molestation. The following are examples of code that can cause segmentation faults (although, occasionally, other errors such as bus errors might the end result)
Dereferencing a NULL pointer;
Code:
char *x = 0;
*x = 42; /* dereferencing a NULL pointer */
Dereferencing a dangling reference;
Code:
char *x = malloc(10);
free(x); /* x is now a dangling reference */
x[5] = 42;
Falling off the end of an array (another form of the example given by Epo)
Code:
char x[10];
char *y;
int i;
for (y = x; y <= x+10; ++y)
{
*y = 0;
}
for (i = 0; i <= 10; ++i)
{
x[i] = 0;
}
Both of the loops in this last example will yield undefined behaviour (and potentially a segmentation fault) on the last time through the loop. The way to correct it is to change to loop conditions from "y <= x+10" to "y < x+10" and "i <= 10" to "i < 10".