A continuation from previous Module. The source code for this module is:C/C++ pointers program source codes. The lab worksheets for your practice are:C/C++ pointers part 1 andC/C++ pointers part 2. Also the exercises in theIndirection Operator lab worksheet 1,lab worksheet 2 and labworksheet 3.
| 8.7 Arrays And Pointers
data equivalent to &data[0] or a pointer to the array’s first element.
// array, pointer and string #include <stdio.h>
void main() { // an array variable of type char, sized 79 char sentence[80]; // prompt for user input... printf("Enter a line of text:\n"); // read the user input...secure version is gets_s() gets(sentence); // display what has been read by gets() printf("Line of text entered: \n%s\n", sentence); getchar(); }
Output:
Figure 8.8 |
Element of an array are stored in sequential memory locations with the first element in the lowest address.
Subsequent array elements, those with an index greater than 0 are stored at higher addresses.
As mentioned before, array of type int occupies 2 byte of memory and a type float occupies 4 byte. Hence the size is depend on the type and the platform (e.g. 32, 64 bits system).
So, forfloat type, each element is located 4 bytes higher than the preceding element, and the address of each array element is 4 higher than the address of the preceding element.
For example, relationship between array storage and addresses for a 6-elements int array and a 3-elements float array is illustrated below.

Figure 8.9
Thex variable without the array brackets is the address of the first element of the array, x[0].
The element is at address of 1000; the second element is1002 and so on.
As conclusion, to access successive elements of an array of a particular data type, a pointer must be increased by the sizeof(data_type). sizeof() function returns the size in bytes of a C/C++ data type. Let take a look at the following example:
// demonstrates the relationship between addresses
// and elements of arrays of different data type
#include <stdio.h>
void main()
{
// declare three arrays and a counter variable
int i[10], x;
float f[10];
double d[10];
// print the table heading
printf("\nArray's el. add of i[x] add of f[x] add of d[x]");
printf("\n|================================");
printf("======================|");
// print the addresses of each array element
for(x=0; x<10; x++)
printf("\nElement %d:\t%p\t%p\t%p",x,&i[x],&f[x],&d[x]);
printf("\n|================================");
printf("======================|\n");
printf("\nLegends:");
printf("\nel.- element, add - address\n");
printf("\ndifferent pc, shows different addresses\n");
}

Notice the difference between the element addresses.
12FEB4 – 12FEB0 = 4 bytes for int
12FE78 – 12FE74 = 4 bytes float
12FE24 – 12FE1C = 8 bytes double
The size of the data type depends on the specification of your compiler, whether your target is 16, 32 or 64 bits systems, the output of the program may be different for different PC. The addresses also may different.
Try another program example.
// demonstrates the use of pointer arithmetic to access
// array elements with pointer notation
#include <stdio.h>
#define MAX 10
void main()
{
// declare and initialize an integer array
int array1[MAX] = {0,1,2,3,4,5,6,7,8,9};
// declare a pointer to int and an int variable
int *ptr1, count;
// declare and initialize a float array
float array2[MAX] = {0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
// declare a pointer to float
float *ptr2;
// initialize the pointers
// just an array name is the pointer to the
// 1st array element, both left value and right value
// of the expression are pointers types...
ptr1 = array1;
ptr2 = array2;
// print the array elements
printf("\narray1 values array2 values");
printf("\n-------------------------");
// iterate or loop the arrays and display the content...
for(count = 0; count < MAX; count++)
printf("\n%d\t\t%f", *ptr1++, *ptr2++);
printf("\n-------------------------\n");
}

Let make it clear, if an array named list[ ] is a declared array, the expression *list is the array’s first element, *(list + 1) is the array’s second element, and so on.
Generally, the relationship is as follows:
*(list) == list[0] // first element
*(list + 1) == list[1] // second element
*(list + 2) == list[2] // third element
...
...
*(array + n) == list[n] // the nth element
So, you can see the equivalence of array subscript notation and array pointer notation.
Pointers may be arrayed like any other data type. The declaration for anint pointer array of size 20 is:
int *arrayPtr[20];
To assign the address of an integer variables called var to the first element of the array, we could write something like this:
// assign the address of variable var to the first arrayPtr element
arrayPtr[0] = &var;
Graphically can be depicted as follows:

Figure 8.10
To find the value stored in var, we could write something like this:
*arrayPtr[0]
To pass an array of pointers to a function, we simply call the function with the array’s name without any index/subscript, because this is an automatically a pointer to the first element of the array, as explained before.
For example, to pass the array named arrayPtr toviewArray function, we write the following statement:
viewArray(arrayPtr);
The following program example demonstrates the passing of a pointer array to a function. It first declares and initializes the array variablevar (not a pointer array).
Then it assigns the address of each element (var[i]) to the corresponding pointer element (arrayPtr[i]).
Next, the arrayarrayPtr is passed to the array’s parameterq in the function viewArray(). The function displays the elements pointed to by q (that is the values of the elements in array var) and then passes control back to main().
// a program that passes a pointer array to a function
#include <iostream>
using namespace std;
// a function prototype for viewArray
void viewArray(int *[ ]);
void main()
{
// declare and initialize the array variables...
int i,*arrayPtr[7], var[7]={3,4,4,2,1,3,1};
// loop through the array...
for(i=0; i<7; i++)
// arrayPtr[i] is assigned with the address of var[i]
arrayPtr[i] = &var[i];
// a call to function viewArray,
// pass along the pointer to the
//1st array element
viewArray(arrayPtr);
cout<<endl;
}
// an arrayPtr is now passed to parameter q,
// q[i] now points to var[i]
void viewArray(int*q[ ])
{
int j;
// displays the element var[i] pointed to by q[j]
// followed by a space. No value is returned
// and control reverts to main()
for(j = 0; j < 7; j++)
cout<<*q[j]<<" ";
}

-----------------------------------------------------------------------------------------------
Graphically, the construct of a pointer to pointer can be depicted as shown below. pointer_one is the first pointer, pointing to the second pointer, pointer_two and finallypointer_two is pointing to a normal variablenum that hold integer 10.

Figure 8.11
Another explanation, from the following figure, a pointer to a variable (first figure) is a single indirection but if a pointer points to another pointer (the second figure), then we have a double or multiple indirections.

Figure 8.12
For the second figure, the second pointer is not a pointer to an ordinary variable, but rather, a pointer to another pointer that points to an ordinary pointer.
In other words, the second pointer points to the first pointer, which in turn points to the variable that contains the data value.
In order to indirectly access the target value pointed to by a pointer to a pointer, the asterisk operator must be applied twice. For example, the following declaration:
int **SecondPtr;
The code tells the compiler that SecondPtr is a pointer to a pointer of type integer. Pointer to pointer is rarely used but you will find it regularly in programs that accept argument(s) from command line.
Consider the following declarations:
char chs; /* a normal character variable */char *ptchs; /* a pointer to a character */char **ptptchs; /* a pointer to a pointer to a character */If the variables are related as shown below:

Figure 8.13
We can do some assignment like this:
chs = 'A';
ptpch = &chs;
ptptpch = ptchs;
Recall thatchar * refers to a NULL terminated string. So one common way is to declare a pointer to a pointer to a string something like this:

Figure 8.14
Taking this one stage further we can have several strings being pointed to by the integer pointers (instead of char) as shown below.

Figure 8.15
Then, we can refer to the individual string by using ptptchs[0],ptptchs[1],…. and generally, this is identical to declaring:
char *ptptchs[ ] /* an array of pointer */
Or from Figure 8.15:
char **ptptchs
Thus, programs that accept argument(s) through command line, the main() parameter list is declared as follows:
int main(int argc, char **argv)
Or something like this:
int main(int argc, char *argv[ ])
Where theargc (argument counter) andargv (argument vector) are equivalent toptchs and ptptchs respectively.
For example, program that accept command line argument(s) such asecho:
C:\>echo This is command line argument
This is command line argument

Here we have:

Figure 8.16
So ourmain() function now has its own arguments. As a convention, these are the only argumentsmain() accepts. Notice that theargv[0] is a application name.
argc (argument counter) is thenumber of arguments (unsigned integer), which we typed including the program name (that is equal to0).
argv (argument vector) is an array of strings (argv[0], argv[1], argv[2],...) holding each command line argument including the program name that is the first array element,argv[0].
But some implementation will have another third parameter,envp/env, a pointer to an environment variable as shown below. Environment variable in Operating System is an array of strings.
int main(int argc, char *argv[ ], *envp[ ])
Let try a program example:
/* a program to print arguments from command line */
/* run this program at the command prompt */
#include <stdio.h>
/*orint main(int argc, *argv[ ])*/
int main(int argc, char **argv)
{
int i;
printf("argc = %d\n\n", argc);
for (i=0; i<argc; ++i)
printf("argv[%d]: %s\n", i, argv[i]);
return 0;
}

Another silly program example :o):
// pointer to pointer...
#include <stdio.h>
int main(void)
{
int **theptr;
int *anotherptr;
int data = 200;
anotherptr = &data;
// assign the second pointer address to the first pointer...
theptr = &anotherptr;
printf("The actual data, **theptr = %d\n", **theptr);
printf("\nThe actual data, *anotherptr = %d\n", *anotherptr);
printf("\nThe first pointer pointing to an address, theptr = %p\n", theptr);
printf("\nThis should be the second pointer address, &anotherptr = %p\n", &anotherptr);
printf("\nThe second pointer pointing to address(= hold data),\nanotherptr = %p\n", anotherptr);
printf("\nThen, its own address, &anotherptr = %p\n", &anotherptr);
printf("\nThe address of the actual data, &data = %p\n", &data);
printf("\nNormal variable, the data = %d\n", data);
return 0;
}

Because of C functions have addresses we can use pointers to point to C functions. If we know the function’s address then we can point to it, which provides another way to invoke it.
Function pointers are pointer variables which point to functions. Function pointers can be declared, assigned values and then used to access the functions they point to. The declaration is as the following:
int (*funptr)();Here,funptr is declared as a pointer to a function that returns int data type.
The interpretation is the de-referenced value of funptr, that is (*funptr) followed by() which indicates a function, which returns integer data type.
The parentheses are essential in the declarations because of the operators’ precedence. The declaration without the parentheses as the following:
int *funptr();
Will declare a function funptr that returns an integer pointer that is not our intention in this case. In C, the name of a function, used in an expression by itself, is a pointer to that function. For example, if a function, testfun() is declared as follows:
int testfun(int x);The name of this function, testfun is a pointer to that function. Then, we can assign them to pointer variablefunptr, something like this:
funptr = testfun;The function can now be accessed or called, by dereferencing the function pointer:
/* calls testfun() with x as an argument then assign to the variable y */y = (*funptr)(x);Function pointers can be passed as parameters in function calls and can be returned as function values.
Use of function pointers as parameters makes for flexible functions and programs. It’s common to use typedefs with complex types such as function pointers. You can use this typedef name to hide the cumbersome syntax of function pointers. For example, after defining:
typedef int (*funptr)();The identifierfunptr is now a synonym for the type of ‘a pointer to function takes no arguments, returning int type’. This typedef would make declaring pointers such as testvar as shown below, considerably easier:
funptr testvar;Another example, you can use this type in a sizeof() expression or as a function parameter as shown below:
/* get the size of a function pointer */
unsigned ptrsize = sizeof (int (*funptr)());
/* used as a function parameter */
void signal(int (*funptr)());
Let try a simple program example using function pointer.
/* invoking function using function pointer */
#include <stdio.h>
int somedisplay();
int main()
{
int (*func_ptr)();
/* assigning a function to function pointer
as normal variable assignment */
func_ptr = somedisplay;
/* checking the address of function */
printf("\nAddress of function somedisplay() is %p", func_ptr);
/* invokes the function somedisplay() */
(*func_ptr)() ;
return 0;
}
int somedisplay()
{
printf("\n--Displaying some texts--\n");
return 0;
}

Another example with an argument.
#include <stdio.h>
/* function prototypes */
void funct1(int);
void funct2(int);
/* making FuncType an alias for the type
'function with one int argument and no return value'.
This means the type of func_ptr is 'pointer to function
with one int argument and no return value'. */
typedefvoid FuncType(int);
int main(void)
{
FuncType *func_ptr;
/* put the address of funct1 into func_ptr */
func_ptr = funct1;
/* call the function pointed to by func_ptr with an argument of 100 */
(*func_ptr)(100);
/* put the address of funct2 into func_ptr */
func_ptr = funct2;
/* call the function pointed to by func_ptr with an argument of 200 */
(*func_ptr)(200);
return 0;
}
/* function definitions */
void funct1 (testarg)
{printf("funct1 got an argument of %d\n", testarg);}
void funct2 (testarg)
{printf("funct2 got an argument of %d\n", testarg);}

The following codes in the program example:
func_ptr = funct1;
(*func_ptr)(100);Can also be written as:
func_ptr = &funct1;(*func_ptr)(100);Or
func_ptr = &funct1;func_ptr(100);Or
func_ptr = funct1;func_ptr(100);As we have discussed before, we can have an array of pointers to an int,float and string. Similarly we can have an array of pointers to a function. It is illustrated in the following program example.
/* an array of pointers to function */
#include <stdio.h>
/* functions' prototypes */
int fun1(int, double);
int fun2(int, double);
int fun3(int, double);
/* an array of a function pointers */
int (*p[3]) (int, double);
int main()
{
int i;
/* assigning address of functions to array pointers */
p[0] = fun1;
p[1] = fun2;
p[2] = fun3;
/* calling an array of function pointers with arguments */
for(i = 0; i <= 2; i++)
(*p[i]) (100, 1.234);
return 0;
}
/* functions' definition */
int fun1(int a, double b)
{
printf("a = %d b = %f", a, b);
return 0;
}
int fun2(int c, double d)
{
printf("\nc = %d d = %f", c, d);
return 0;
}
int fun3(int e, double f)
{
printf("\ne = %d f = %f\n", e, f);
return 0;
}

In the above program we take an array of pointers to function int (*p[3]) (int, double). Then, we store the addresses of three function fun1(), fun2(),fun3() in array (int *p[ ]). In the for loop we consecutively call each function using their addresses stored in array.
For function and array, the only way an array can be passed to a function is by means of a pointer.
Before this, an argument is a value that the calling program passes to a function. It can be int, a float or any other simple data type, but it has to be a single numerical value.
The argument can, therefore, be a single array element, but it cannot be an entire array.
If an entire array needs to be passed to a function, then you must use a pointer.
As said before, a pointer to an array is a single numeric value (the address of the array’s first element).
Once the value of the pointer (memory address) is passed to the function, the function knows the address of the array and can access the array elements using pointer notation.
Then how does the function know the size of the array whose address it was passed?
Remember! The value passed to a function is a pointer to the first array element. It could be the first of 10 elements or the first of 10000 or what ever the array size.
The method used for letting a function knows an array’s size, is by passing the function the array size as a simple int type argument.
Thus the function receives two arguments:
A pointer to the first array element and
An integer specifying the number of elements in the array, the array size.
The following program example illustrates the use of a pointer to a function. It uses the function prototype float (*ptr) (float, float) to specify the number and types of arguments. The statementptr = &minimum assigns the address ofminimum() to ptr.
The statementsmall = (*ptr)(x1, x2); calls the function pointed to by (*ptr), that is the functionminimum() which then returns the smaller of the two values.
// pointer to a function
#include <iostream>
using namespace std;
// function prototypes...
float minimum(float, float);
// (*ptr) is a pointer to function of type float
float (*ptr)(float, float);
void main()
{
float x1, x2, small;
// assigning address of minimum() function to ptr
ptr = minimum;
cout<<"\nEnter two numbers, separated by space: ";
cin>>x1>>x2;
// call the function pointed by ptr small has the return value
small = (*ptr)(x1, x2);
cout<<"\smaller number is "<<small<<endl;
}
float minimum(float y1, float y2)
{
if (y1 < y2)
return y1;
else
return y2;
}

Study the program's source code and the output.
Also the exercises in theIndirection Operator lab worksheet 1,lab worksheet 2 and labworksheet 3.