That mysterious independent variable of political calculations, Public Opinion.
In constructing our building, we have identified each brick (variable) by name. That process is fine for a small number of bricks, but what happens when we want to construct something larger? We would like to point to a stack of bricks and say, “That’s for the left wall. That’s brick 1, brick 2, brick 3...”
Arrays allow us to do something similar with variables. An array is a set of consecutive memory locations used to store data. Each item in the array is called an element. The number of elements in an array is called the dimension of the array. A typical array declaration is:
/* List of data to be sorted and averaged */ int data_list[3];
The above example declares data_list
to be an array of three elements.
data_list[0]
, data_list[1]
, and data_list[2]
are separate variables. To
reference an element of an array, you use a number called the
index—the number inside the square brackets ([ ]). C is a funny
language that likes to start counting at 0. So, our three elements are
numbered to 2.
Common sense tells you that when you declare data_list
to be three elements long,
data_list[3]
would be valid.
Common sense is wrong and data_list[3]
is illegal.
Example 5-1 computes the total and average of five numbers.
[File: array/array.c] #include <stdio.h> float data[5]; /* data to average and total */ float total; /* the total of the data items */ float average; /* average of the items */ int main() { data[0] = 34.0; data[1] = 27.0; data[2] = 45.0; data[3] = 82.0; data[4] = 22.0; total = data[0] + data[1] + data[2] + data[3] + data[4]; average = total / 5.0; printf("Total %f Average %f ", total, average); return (0); }
This program outputs:
Total 210.000000 Average 42.000000
Strings are sequences of characters. C does not have a
built-in string type; instead, strings are created out of character
arrays. In fact, strings are just character arrays with a few
restrictions. One of these restrictions is that the special character
' '
(NUL) is used to indicate the
end of a string.
For example:
char name[4]; int main() { name[0] = 'S'; name[1] = 'a'; name[2] = 'm'; name[3] = ' '; return (0); }
This code creates a character array of four elements. Note that we had to allocate one character for the end-of-string marker.
String constants consist of text enclosed in double
quotes (""
). You may have noticed
that the first parameter to printf
is a string constant. C does not allow one array to be assigned to
another, so we can’t write an assignment of the form:
name = "Sam"; /* Illegal */
Instead we must use the standard library function
strcpy
to copy the string constant
into the variable. (strcpy
copies
the whole string, including the end-of-string character.) To
initialize the variable name
to
Sam
, we would write:
#include <string.h> char name[4]; int main() { strcpy(name, "Sam"); /* Legal */ return (0); }
C uses variable-length strings. For example, the declaration:
#include <string.h> char string[50]; int main() { strcpy(string,"Sam"); }
creates an array (string
)
that can contain up to 50 characters. The size of the array is 50, but
the length of the string is 3. Any string up to 49 characters long can
be stored in string
. (One character
is reserved for the NUL that indicates end-of-string.)
String and character constants are very different. Strings are
surrounded by double quotes ("
)
and characters by single quotes ('
). So "X"
is a one-character string, while
'Y'
is just a single character.
(The string "X"
takes up two
bytes, one for the X and one for the end-of-string ( ). The
character 'Y'
takes up one
byte.)
There are several standard routines that work on string variables, as shown in Table 5-1.
Function | Description |
| Copy |
| Concatenate |
| Get the length of a
|
| 0if otherwise nonzero |
The printf
function uses
the conversion %s
for printing
string variables, as shown in Example
5-2.
#include <string.h> #include <stdio.h> char name[30]; /* First name of someone */ int main() { strcpy(name, "Sam"); /* Initialize the name */ printf("The name is %s ", name); return (0); }
Example 5-3 takes a first name and a last name and combines the two strings.
The program works by initializing the variable first
to the first name (Steve). The last
name (Oualline) is put in the variable last
. To construct the full name, the first
name is copied into full_name
. Then
strcat
is used to add a space. We
call strcat
again to tack on the
last name.
The dimension of the string variable is 100 because we know that no one we are going to encounter has a name more than 99 characters long. (If we get a name more than 99 characters long, our program will mess up. What actually happens is that you write into memory that you shouldn’t access. This access can cause your program to crash, run normally and give incorrect results, or behave in other unexpected ways.)
#include <string.h> #include <stdio.h> char first[100]; /* first name */ char last[100]; /* last name */ char full_name[200]; /* full version of first and last name */ int main() { strcpy(first, "Steve"); /* Initialize first name */ strcpy(last, "Oualline"); /* Initialize last name */ strcpy(full_name, first); /* full = "Steve" */ /* Note: strcat not strcpy */ strcat(full_name, " "); /* full = "Steve " */ strcat(full_name, last); /* full = "Steve Oualline" */ printf("The full name is %s ", full_name); return (0); }
The output of this program is:
The full name is Steve Oualline
The standard function fgets
can be used to read a string from the
keyboard. The general form of an fgets
call is:
fgets(name
, sizeof(name
), stdin);
where name identifies a string variable.
(fgets
will be explained in detail
in Chapter 14.)
The arguments are:
is the name of a character array. The line (including the end-of-line character) is read into this array.
sizeof(
name)
indicates the maximum number of characters to read (plus
one for the end-of-string character). The sizeof
function provides a convenient
way of limiting the number of characters read to the maximum
numbers that the variable can hold. This function will be
discussed in more detail in Chapter
14.
stdin
is the file to read. In this case, the file is the standard input or keyboard. Other files are discussed in Chapter 14.
Example 5-4 reads a line from the keyboard and reports its length.
#include <string.h> #include <stdio.h> char line[100]; /* Line we are looking at */ int main() { printf("Enter a line: "); fgets(line, sizeof(line), stdin); printf("The length of the line is: %d ", strlen(line)); return (0); }
When we run this program, we get:
Enter a line:test
The length of the line is:5
But the string test
is only
four characters. Where’s the extra character coming from? fgets
includes the end-of-line in the
string. So the fifth character is newline (
).
Suppose we wanted to change our name program to ask the user for his first and last name. Example 5-5 shows how we could write the program.
#include <stdio.h> #include <string.h> char first[100]; /* First name of person we are working with */ char last[100]; /* His last name */ /* First and last name of the person (computed) */ char full[200]; int main() { printf("Enter first name: "); fgets(first, sizeof(first), stdin); printf("Enter last name: "); fgets(last, sizeof(last), stdin); strcpy(full, first); strcat(full, " "); strcat(full, last); printf("The name is %s ", full); return (0); }
However, when we run this program we get the results:
%name2
Enter first name:John
Enter last name:Doe
The name is John Doe %
What we wanted was “John Doe” on the same line. What happened?
The fgets
function gets the entire
line, including the end-of-line. We must get rid
of this character before printing.
For example, the name “John” would be stored as:
first[0] = 'J' first[1] = 'o' first[2] = 'h' first[3] = 'n' first[4] = ' ' first[5] = ' ' /* end of string */
By setting first[4]
to NUL
('
'), we can shorten the string
by one character and get rid of the unwanted newline. This change can
be done with the statement:
first[4] = ' ';
The problem is that this method will work only for four-character names. We need a general algorithm to solve this problem. The length of this string is the index of the end-of-string null character. The character before it is the one we want to get rid of. So, to trim the string, we use the statement:
first[strlen(first)-1] = ' ';
Our new program is shown in Example 5-6.
#include <stdio.h> #include <string.h> char first[100]; /* First name of person we are working with */ char last[100]; /* His last name */ /* First and last name of the person (computed) */ char full[200]; int main() { printf("Enter first name: "); fgets(first, sizeof(first), stdin); /* trim off last character */ first[strlen(first)-1] = ' '; printf("Enter last name: "); fgets(last, sizeof(last), stdin); /* trim off last character */ last[strlen(last)-1] = ' '; strcpy(full, first); strcat(full, " "); strcat(full, last); printf("The name is %s ", full); return (0); }
Running this program gives us the following results:
Enter first name:John
Enter last name:Smith
The name is John Smith
Arrays can have more than one dimension. The declaration for a two-dimensional array is:
type variable
[size1
][size2
]; /*Comment
*/
For example:
int matrix[2][4]; /* a typical matrix */
Notice that C does not follow the notation
used in other languages of matrix[10,12]
.
To access an element of the matrix
, we use the notation:
matrix[1][2] = 10;
C allows the programmer to use as many dimensions as needed (limited only by the amount of memory available). Additional dimensions can be tacked on:
four_dimensions[10][12][9][5];
Question 5-1: Why does Example 5-7 print the wrong answer? (Click here for the answer Section 5.15)
#include <stdio.h> int array[3][2]; /* Array of numbers */ int main() { int x,y; /* Loop indicies */ array[0][0] = 0 * 10 + 0; array[0][1] = 0 * 10 + 1; array[1][0] = 1 * 10 + 0; array[1][1] = 1 * 10 + 1; array[2][0] = 2 * 10 + 0; array[2][1] = 2 * 10 + 1; printf("array[%d] ", 0); printf("%d ", array[0,0]); printf("%d ", array[0,1]); printf(" "); printf("array[%d] ", 1); printf("%d ", array[1,0]); printf("%d ", array[1,1]); printf(" "); printf("array[%d] ", 2); printf("%d ", array[2,0]); printf("%d ", array[2,1]); printf(" "); return (0); }
So far, we have only read simple strings, but we want more. We
want to read numbers as well. The function scanf
works like printf,
except that scanf
reads numbers instead of writing them.
scanf
provides a simple and easy
way of reading numbers that almost never works.
The function scanf
is notorious for
its poor end-of-line handling, which makes scanf
useless for all but an expert.
However, we’ve found a simple way to get around the deficiencies
of scanf
—we don’t use it. Instead,
we use fgets
to read a line of
input and sscanf
to convert the
text into numbers. (The name sscanf
stands for “string scanf
“. sscanf
is like scanf,
but works on strings instead of the
standard input.)
Normally, we use the variable line
for lines read from the
keyboard:
char line[100]; /* Line of keyboard input */
When we want to process input, we use the statements:
fgets(line, sizeof(line), stdin); sscanf(line,format
, &variable1
, &variable2
. . .;
Here fgets
reads a line and
sscanf
processes it.
format is a string similar to the printf
format string. Note the ampersand
(&
) in front of the variable
names. This symbol is used to indicate that sscanf
will change the value of the
associated variables. (For information on why we need the ampersand,
see Chapter 13.)
If you forget to put &
in front of each variable for sscanf
, the result could be a
“Segmentation violation core dumped” or “Illegal memory access”
error. In some cases a random variable or instruction will be
changed. On UNIX, damage is limited to the current program; however,
on MS-DOS/Windows, with its lack of memory protection, this error
can easily cause more damage. On MS-DOS/Windows, omitting &
can cause a program or system
crash.
In Example 5-8, we use
sscanf
to get and then double a
number from the user.
[File: double/double.c] #include <stdio.h> char line[100]; /* input line from console */ int value; /* a value to double */ int main() { printf("Enter a value: "); fgets(line, sizeof(line), stdin); sscanf(line, "%d", &value); printf("Twice %d is %d ", value, value * 2); return (0); }
This program reads in a single number and then doubles it.
Notice that there is no
at the
end of Enter a value:
. This
omission is intentional because we do not want the computer to print a
newline after the prompt. For example, a sample run of the program
might look like:
Enter a value:12
Twice 12 is 24
If we replaced Enter a value:
with Enter a value:
, the result
would be:
Enter a value:12
Twice 12 is 24
Question 5-2: Example 5-9 computes the area of a
triangle, given the triangle’s width and height. For some strange
reason, the compiler refuses to believe that we declared the variable
width
. The declaration is right
there on line 2, just after the definition of height. Why isn’t the
compiler seeing it? (Click here for the answer Section 5.15)
#include <stdio.h> char line[100];/* line of input data */ int height; /* the height of the triangle int width; /* the width of the triangle */ int area; /* area of the triangle (computed) */ int main() { printf("Enter width height? "); fgets(line, sizeof(line), stdin); sscanf(line, "%d %d", &width, &height); area = (width * height) / 2; printf("The area is %d ", area); return (0); }
C allows variables to be initialized in the declaration
statement. For example, the following statement declares the integer
counter
and initializes it to
0
:
int counter = 0; /* number cases counted so far */
Arrays can also be initialized in this manner. The element list must be enclosed in curly braces ({}). For example:
/* Product numbers for the parts we are making */ int product_codes[3] = {10, 972, 45};
The previous initialization is equivalent to:
product_codes[0] = 10; product_codes[1] = 972; product_codes[2] = 45;
The number of elements in {} does not have to match the array size. If too many numbers are present, a warning will be issued. If an insufficient amount of numbers are present, C will initialize the extra elements to 0.
If no dimension is given, C will determine the dimension from
the number of elements in the initialization list. For example, we
could have initialized our variable product_codes
with the statement:
/* Product numbers for the parts we are making */ int product_codes[] = {10, 972, 45};
Initializing multidimensional arrays is similar to initializing single-dimension arrays. A set of brackets ([ ]) encloses each dimension. The declaration:
int matrix[2][4]; /* a typical matrix */
can be thought of as a declaration of an array of dimension 2 with elements that are arrays of dimension 4. This array is initialized as follows:
/* a typical matrix */ int matrix[2][4] = { {1, 2, 3, 4}, {10, 20, 30, 40} };
Strings can be initialized in a similar manner. For
example, to initialize the variable name
to the string “Sam”, we use the
statement:
char name[] = {'S', 'a', 'm', ' '};
C has a special shorthand for initializing strings: Surround the
string with double quotes (""
) to
simplify initialization. The previous example could have been written:
char name[] = "Sam";
The dimension of name
is 4,
because C allocates a place for the '