A multi-dimensional array is just an array of arrays
We declare a 2 dimensional array with:
int a[10][20];
int x;
This can be viewed as 10 arrays, each of which contain 20 integer elements
An individual element of this array is retrieved with:
x = a[i][j];
Naturally we can still do things like the following
int* pa;
pa = &a[0][0]; /* or even pa = a; */
x = *(pa+i*20+j); /* x = a[i][j]; */
Similarly we can do things like:
int a[10][20];
int (*pa)[20]; /* see last note below */
pa = &a[0]; /* pa = &a[0][0]; */
Then (*pa)[5] would be the same as a[0][5]
An observation: A variable is declared in the way that it is used
The type in a variable declaration is usually a basic type, the declaration syntax shows how a value of that basic type can be obtained from the variable name
Also note that [] has higher precedence than *, so we need to use parenthesis in the above declaration, otherwise we would have an array of 20 pointers to integers instead of a pointer to an array of 20 integers
Character Arrays and Initialization
An array of pointers to text strings (which is not the same as a 2 dimensional array of characters) is often used in C programming. Such a structure can be initialized in the following way:
char* name[] = {"George", "Mark", "Peter", "Jimmy"};
The last element of the array should be NULL, to serves as a marker. We can detect the end of the array in the following way:
#define INFINITY 32767 /* 2^15 - 1 */
#define NULL
0
if (name[i]
== NULL)
} /*
but what is the value of i? */
1 Mark
2 Peter
3 Jimmy
4 ™? int i = 0;
5 while (name[i++] != NULL);
Consider now the assignment statement
name[2] = "Paul"; /* replace "Peter" by "Paul" */
Note that the compiler has built the string constant "Paul" and the assignment causes name[2] to point to it.
The space that "Peter" used is still in existence, but is now inaccessible. Later we will see how to manage this memory loss better.
See King pages 262 and 263
Consider another way of forming this matrix of names:
char name[][7] = {"George", "Mark", "Peter", "Jimmy"};
This is your customary 2-D array formation. Thus in C we have two similar but distinctly different ways of forming multidimensional arrays. The first one above is the more efficient in terms of storage space, but uses pointers. Also the use of char* (string) variables warrants use of the special system functions in <string.h> and you will have to become familiar with these, especially strcpy, strcmp, and strlen
Functions and Procedures
There are two ways of declaring and defining procedures in C, the old way and the ANSI standard way - you may run into both, but use only ANSI form
All procedures in C are really functions, that is they return a value. The special type void indicates that a return value is not used (not wanted). Such void functions are called procedures.
C has both function declarations and function definitions - these are two different concepts
A function declaration contains all the information required to call the function, that is the name the types of the parameters and the type of the return value. These declarations are also called prototypes.
A function definition includes all the information in a function declaration, plus local variables and the statements in the function - It not only describes how the function can be called, but also how it computes its value
Function Declarations (ANSI prototype)
type FunctionName ( ParameterDeclarations );
For example:
float Work
(int x, double y, char* s);
float Work
(int , double , char* );
The parameters in the prototype are in the order of the function definition (no surprise there).
Function Definitions
The ANSI style of function definition is:
type FunctionName (ParameterDeclarations) {
local variable declarations;
statements;
return (expression);
}
A return statement is used to supply the value of the function and to give control back to the calling program
Formats of the return statement are:
return (Rvalue); or return Rvalue;
and
return ; /* used only with void functions */
Although the return can be omitted in that case.
Parameter Passing
All parameter passing in C is by value, that is, when a function is called the parameter values from the calling function are copied into temporary storage in the called function--all modifications to the parameter values occur in this temporary storage; the original values in the calling function are not changed
This means that you cannot return a result directly through a parameter. The only way to export a result with a parameter is to do so indirectly through a pointer to the location where the result will be stored
Remember arrays are built with pointers, so if you pass an array address (not an array element) to a function, you can modify the elements in the array and these changes will be seen outside of the function
void initialize (int x) {
we can do anything we like to x inside this function.
The calling function won't see any of these changes.
It provides only the initial value of x
x = 5;
}
but consider ::::::::
void reset (int* y) {
*y = 5; /* put 5 in cell pointed to by y */
}
int i = 3, j = 3;
initialize ( i );
reset ( &j );
printf ( "%d, %d", i, j );
This will print 3, 5, since we have passed a pointer to j into the function, the value pointed at is changed by the reset - note that the invocation reset (j) will cause all sorts of problems, since the parameter j isn't a pointer.
When would j be a pointer?
int j[10];
then
reset (j); is the same as reset ( &j[0] );
thus the parameter j is a pointer. HOWEVER, the corresponding formal parameter would still be
void reset ( int* y );
The ReadLine and FetchLine functions, below, are equivalent, but their parameter declarations are appropriate for their intended use
#include <stdio.h>
int ReadLine ( char str[], int n )
{
int i = 0;
while ( (ch
= getchar()) != '\n' ) {
str[i++] = ch;
}
str[i] = '\0';
return (i);
int FetchLine (char* str, int n)
{
int i = 0;
while ( (ch
= getchar()) != '\n' ) {
*(str+i++)
= ch;
*(str+i) = '\0';
return (i);
They are used in the following way:
void main (void) {
int m;
m = ReadLine (message, 16);
printf ("%d chars in:%s\n", m, message);
m = FetchLine (&message[0], 16);
printf ("%d chars in:%s\n", m, message);
When you call a function, the actual
parameters (arguments) to the function are copied and placed onto the stack.
Thus the function manipulates copies of the parameters, not the original
arguments themselves. That is, all function calls in C are call by value.
To alter
a data object in the calling program you must either return a value from
the function, or pass the address of the object
to the function.
Just to convince you that arguments are copied:
#include <stdio.h>
void look (int
a, int b, char c, char d, double f, double g) {
printf ("The address of argument b is %x\n", (int) &b);
printf ("The address of argument c is %x\n", (int) &c);
printf ("The address of argument d is %x\n", (int) &d);
printf ("The address of argument f is %x\n", (int) &f);
printf ("The address of argument g is %x\n", (int) &g);
}
/*
The previous is a procedure called "look" that prints 8 lines of output. Each line has a single number that is the address of a different parameter--coerced from an unsigned int to an int and printed in hexadecimal (%x)
*/
int main (void) {
static int b = 2;
static char c = '3'; /* 1 byte of space */
static char d = '4';
static double f = 5.0; /* 8 bytes of space */
static double g = 6.0;
printf ("The address of a is %x\n", (int) &a);
printf ("The address of b is %x\n", (int) &b);
printf ("The address of c is %x\n", (int) &c);
printf ("The address of d is %x\n", (int) &d);
printf ("The address of f is %x\n", (int) &f);
printf ("The address of g is %x\n", (int) &g);
look (a, b, c, d, f, g);
return (0);
produces output like
The address of a is 40b0
The address of b is 40b4
The address of c is 40b8
The address of d is 40b9
The address of f is 40c0 why not 40ba ?
The address of g is 40c8
Run this program and discuss the remaining output with your TA
The address of argument a is effff874 4 bytes
The address of argument b is effff878
The address of argument c is effff827 1 byte
The address of argument d is effff826
The address of argument f is effff818 8 bytes
The address of argument g is effff810
Note the size of the (stack) addresses!!
Why are they not at 4-byte intervals?