Chapter 7 Arrays
The concept of an array is common to most programming languages.
In an array, multiple values of the same data type can be stored
with one variable name. The use of arrays allows for the
development of smaller and more clearly readable programs.
7.1 Arrays
Arrays are classified as aggregate data types. Unlike atomic
data types which cannot be subdivied, aggregate data types are
composed of one or more elements of an atomic or another
aggregate data type. Simply put aggregate data types can be
subdivided or broken down. To access individual elements of an
array a subscript must be used. The subscript identifies the
sub-element or component of the array that is to be accessed.
Subscripts must start at 0 and proceed in increments of 1.
Arrays can be of any data type supported by C, including
constructed data types and arrays can be of any storage class
except 'register'.
7.1.1 Declaring and Initialization
Arrays can be declared as local variables or global variables.
Initialization of an array when it is declared is allowed for
both locally and globally declared arrays. Initializing an array
when it is declared does not require the presence of a dimension
on the array
Fig. 7-1
char name[] = "John Smith";
int age[] = {21,32,43,22,25};
main()
{
.
.
.
}
OR
main()
{
int age[] = {21,32,43,22,25};
.
.
.
}
If an array is declared to hold ten elements, the subscripts
start at 0 and the highest subscript allowed for that array is 9.
There is no bounds checking on arrays. It is the programmers
responsibility to keep the subscript within the bounds of the
array. On the above array age, which has five elements if a
statement such as
age[6] = 10;
is made in the program, no error or warning will be generated by
the compiler. The array age should only support subscripts
ranging from 0 to 5. A subscript of 6 is not within the bounds
of the array, but C/C++ will allow the statement. In most cases
the program will terminate with a runtime error because of the
above statement.
7.1.2 Multi-Dimensional Arrays
Two and three dimensional arrays are allowed but actually there
is no limit on the number of dimensions for an array.
int aver[10][20];
float sales[50][10][2];
Values in a multi-dimensional array are stored in row-major
order, meaning that if array is declared as
int data[3][4];
the values are stored in memory in this order
[0][0] [0][1] [0][2] [0][3] [1][0] [1][1] [1][2] [1][3] ...
and so forth. Therefore, when initializing a multi-dimensional
array at declaration time, the row designator does not have to be
stated, but the column length must be stated, such as:
float monthlySalesByProduct[][4] =
{ {100.50, 234.32, 987.98}
, {324.56, 123.43, 876.83}
, {765.23, 8743.28, 27388.87}
...
};
Notice the use of nested {...} pairs to set off the column values
for a row. This is required in order to delineate the boundaries
of the rows. The two-dimensional array above can also be called
a square array. A square array can be used to store arrays of
strings.
Listing 7-1
#include <iostream.h>
int main()
{
char students[10][25]; // holds names of students
int idx;
for( idx = 0; idx < 10; ++idx )
{
cout << "Enter a students first name: ";
cin >> students[idx];
}
cout << "\nThe students in the class are:" << endl;
for( idx = 0; idx < 10; ++idx )
cout << students[idx] << endl;
return 0;
}
Notice the used of students[i] in the above example. The name of
each row in the multi-dimensional array is the name of an array,
which means that it represents the beginning address of where
data is stored. You can use the name of a row the same as you
would the name of an array. Also, notice that no matter how
short the name of the student is, the same number of characters
is allocated for each row, therefore leading to excessing use of
memory space.
7.2 Arrays as Arguments
Arrays are automatically passed by reference to a function. The
name of an array is the beginning address of where the array data
is stored in memory; also known as a 'pointer constant'.
Listing 7-2
#include <iostream.h>
int main()
{
int list[10]
,max = 10
,indx = 0
,largest
,num_ele
;
int find_max( int [], int );
while( indx < max)
{
cout << "\nEnter a number: ";
cin >> list[indx];
++indx;
}
largest = find_max( list, max );
cout << "\nLargest number is " << largest << endl;
return 0;
}
int find_max( int list2[], int size )
{
int
idx
,highest
;
for(highest = list2[0],idx = 1; idx < size; ++idx)
if(highest < list2[idx])
highest = list2[idx];
return(highest);
}
In the find_max() function, list2[] is an array of undetermined
length. On the call to find_max() the argument list is stated
without subscripts, this passes the address of list, because
list is an array. The name of an array is a pointer constant
that represents the beginning address of the array. Therefore,
when list is stated in the call to find_max(), the address that
list represents is actually passed to the function. The
receiving argument list2[] only receives the address of where the
array begins in memory. With the array notation used for the
receiving argument, list2[] can be treated as if it is an alias
that allows for the direct manipulation of the data stored in
list.
Multi Dimensional arrays as arguments follow the same syntax
except that on the receiving side the last dimension must be
stated. This is so the compiler knows where one row of data ends
and another row begins.
Listing 7-3
#include <iostream.h>
#define ROWS 10
#define COLUMNS 2
int main()
{
float agents[ROWS][COLUMNS];
int indx = 0;
int maxex( float [][COLUMNS], int );
cout << "\nEnter 3-digit agent"
<< " number then travel "
<< "expenses(001 1642.50)";
do
{
cout << "\nAgents # and expenses:";
cin >> agents[indx][0]
>> agents[indx][1]);
}while( agents[indx++][0] != 0 );
indx--;
indx = maxex(agents,indx);
cout << "\nAgent with highest expenses: "
<< agents[indx][0];
cout << " Amount: %.2f"
<< agents[indx][1];
return 0;
}
int maxex(float list[][COLUMNS],int size)
{
int
idx
,maxidx
;
float
max
;
max = list[0][1];
maxidx = 0;
for(idx = 1; idx
7.3 Strings
An array of type char ending with a NULL ('\000') character is
called a string in C.
Fig 7-3
char name[] = "John Smith";
main()
{
.
.
.
}
the above string is stored in memory as:
Fig 7-4
memory value
address at address
2000 J
2001 o
2002 h
2003 n
2004
2005 S
2006 m
2007 i
2008 t
2009 h
200A \0
An array that will be used as a string must be declared with one
additional byte more than is needed for data. This allots space
for the NULL byte which is the signal indicating the end of the
string.
Listing 7-4
//
// looks at string in memory
//
#include <iostream.h>
#include <stdio.h>
#include <string.h>
int main()
{
char name[81];
int indx;
cout << "\nEnter your name: ";
gets(name); // used because of whitespace input
cout << "\nThe string " << name
<< " is stored at address "
<< hex << unsigned(name);
for(indx=0; indx < strlen(name); ++indx)
{
cout << "\nADDR: " << hex << unsigned(name);
cout << " CHAR: " << name[indx];
cout << " DEC: " << dec << int(name[indx]);
}
return 0;
}
7.3.1 String Functions<
Strings must be manipulated with standard functions supplied with
the compiler function libraries.
char *strcat(char *str1, char *str2);
Appends str2 to str1, terminates the resulting string with a NULL
character and returns the address of the concatenated string,
str1.
char *strchr(char *str, char c);
Returns the address of the first occurrence of c in str; the
function returns NULL if the character is not found.
int strcmp(char *str1, char *str2);
Compares str1 and str2 lexicographically and returns a value
indicating their relationship.
Value Meaning
< 0 str1 less than str2
0 str1 equal to str2
> 0 str1 greater than str2
int strcmpi(char *str1, char *str2);
Case-insensitive version of strcmp. Strings are compared without
regard to case.
char *strcpy(char *str1, char *str2);
Copies str2, including the null terminating character to location
specified by str1 and returns str1.
int strcspn(char *str1, char *str2);
Returns the index of the first character in str1 that belongs to
the set of characters specified by str2.
char *strdup(char *str);
Allocates storage space for a copy of str and returns the address
to that storage space containing the copied string. Returns NULL
if storage could not be found.
int strlen(char *str);
Returns the length in bytes of str not including the
termininating null character.
char *strlwr(char *str);
Converts any uppercase letters in the given null terminated
string to lowercase.
char *strncat(char *str1, char *str2, int n);
Appends at most the first n characters of str2 to str1,
terminates the resulting string with a null character and returns
the address of the concatenated str1.
int strncmp(char *str1, char *str2, int n);
Compares at most the first n characters of str1 and str2
lexicographically and returns a value indicating the relationship
between the substrings.
Value Meaning
< 0 substring1 < substring2
0 substring1 = substring2
> 0 substring1 > substring2
char *strncpy(char *str1, char * str2, int n);
Copies exactly n characters of str2 to str1 and returns str1.
char *strnset(char *str, char c, int n);
Sets at most the first n characters of str to the character c
and returns the address of the altered str.
char *strtok( char *str, char *delims );
Searches one string for tokens, which are separated by delimiters
defined in a second string.
Listing 7-5
#include <string.h>
#include <stdio.h>
int main()
{
char input[16] = "abc,d";
char *p;
/*
* strtok places a NULL terminator
* in front of the token, if found
*/
p = strtok( input, "," );
if( p )
printf( "%s\n", p);
/*
* a second call to strtok using a
* NULL as the first parameter returns
* a pointer to the character following
* the token
*/
p = strtok( NULL, "," );
if( p )
printf("%s\n", p );
return 0;
}