
Twenty bricks in a row, six rows of them, and each is either there or gone. You are not going to declare a hundred and twenty variables. An array is many values of one type under one name, picked out by a number, and a grid is an array of arrays. This section is arrays, the way this compiler wants them declared, and the thing every C programmer learns the hard way at least once: nothing stops you writing past the end.
int scores[5];
Five ints, called scores[0] to scores[4]. The first is 0 and the last is one less than the size. That is the rule that catches everyone: scores[5] is not the fifth score, it is the one past the end, and the compiler will let you use it (below).
Each scores[i] is an int like any other. The number in the brackets can be a variable or a sum, which is the whole point:
for (i = 0; i < 5; i++)
scores[i] = i * 10;
Note i < 5, not i <= 5. Written with a < and the array's size, a loop over an array is right by construction.
A global array may be given its values where it is declared, and the compiler counts them for you:
int primes[] = { 2, 3, 5, 7, 11 };
A local one may not, as S10 said of every local: int a[3] = { 1, 2, 3 }; inside a function is refused with RESTRICTION: use assignment or blt() to initialise automatics. Declare it, then fill it with a loop, or make it global.
A global array you have not filled starts full of zeros. A local one starts full of whatever was in that memory last, so fill it before you read it.
char board[3][4];
Three rows of four chars: board[row][col], both from 0. The first number is the row and the second the column, and that order is a convention worth keeping, because the screen is described the same way and the game's bricks will be bricks[row][col].
The listing uses a grid of char as a picture: . for empty and S for a piece, with a 0 at the end of each row so that the row can be printed as a string by %s (S17). Three lines of printf, one per row, and the grid is on the screen. That is a first, slow draft of how a game draws its board; S24 does it properly.
total(a, n) int a[], n;
{
An array argument is declared with empty brackets - its size is not part of the type - and the caller passes it by name, total(scores, 5). The size goes separately, because the function has no other way to know it.
And here is the difference from S13: the function gets the array itself, not a copy. a[0] = 100 inside total changes scores[0] in main. That is how a function fills a board or moves the pieces on it, and it is also how a function ruins an array it was only meant to read. S16 explains why arrays behave this way when everything else is copied.
The compiler does not check the index. Not when it compiles, not when it runs. int a[3]; a[3] = 99; compiles, runs, and says nothing. A loop that goes to i <= 3 instead of i < 3 compiles, runs, and says nothing. The 99 is written into whatever happens to live just past the end of a - another variable, part of the machinery that keeps track of where a function returns to, anything.
What happens next depends on what that was. In two runs of exactly those mistakes, nothing visible happened at all. In another, strcpy was used to put an eight-letter word into a char array of four: the program printed the word perfectly, printed the variable declared next to the array perfectly, and then, on its way back to the prompt, dropped into the Einstein's monitor with a register dump - because the extra letters had landed on the address the program needed to get home.
So: an overrun is silent until it is not, and when it is not, the crash is usually somewhere else and later. When a program that was working starts doing something senseless after you added an array, or made one longer, or filled one in a loop, check every index against the size before you look for anything else. < size, never <= size, and strings need one more than their letters (S17).
#include STDIO.H
int primes[] = { 2, 3, 5, 7, 11 };
main()
{
int scores[5], i, total;
char board[3][4];
for (i = 0; i < 5; i++)
scores[i] = i * 10;
total = 0;
for (i = 0; i < 5; i++)
total += scores[i];
printf("total %d, last %d\n", total, scores[4]);
printf("third prime is %d\n", primes[2]);
for (i = 0; i < 3; i++)
board[i][0] = board[i][1] = board[i][2] = '.';
board[1][1] = 'S';
for (i = 0; i < 3; i++) {
board[i][3] = 0;
printf("%s\n", board[i]);
}
}
#include ?STDIO.LIB?
board[i][0] = board[i][1] = board[i][2] = '.' is three assignments in one: = gives a value and is that value, so it can be chained from the right.
Starting from
Typed as ARR.C; compiled and run.
What you should see
total 100, last 40
third prime is 5
...
.S.
...
i < 5 to i <= 5. Compile and run. What is printed, and what does that tell you about where the extra 50 went? Then restart the Einstein anyway.primes[2] to primes[5]. What is printed? Is it an error?int primes[] = ... inside main, after char board[3][4];. What does the compiler say?15.1 Fill an array of ten ints with the squares of 1 to 10 and print them backwards.
15.2 Write biggest(a, n) returning the largest value in an array, and test it.
15.3 Declare char row[41], fill it with twenty #s followed by a 0, and print it. Then print it again with the eleventh # changed to a space.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
RESTRICTION: use assignment or blt() to initialise automatics | = { ... } on a local array. Fill it with a loop, or make it global. |
| A variable near an array changes by itself | An index past the end. |
| A program crashes on the way out of a function, or after it has printed everything correctly | An overrun clobbered the function's return address. Check every index and every string's size. |
| The last element is one you never set | Indexes run from 0 to size - 1. |
| A function that was only supposed to read an array changed it | It has the array itself, not a copy. |
need a type name at sizeof(scores) | sizeof takes a type here, never a variable. Keep the size in a #define (S19). |
type name[size], indexed 0 to size - 1; name[row][col] for a grid. Globals may be initialised with { } and start at zero; locals may not, and start with rubbish. A function receives the array itself. Nothing checks an index, and the damage shows up later and elsewhere.
S16, Pointers - the address of a thing, which is what an array's name really is, what & and * do, and how to write to a fixed place in the Einstein's memory.