Documente Academic
Documente Profesional
Documente Cultură
#include <stdio.h>
In the METHOD 1 above, rptr turned out to be a pointer to int nrows = 5;
type "one dimensional array /* Both nrows and ncols could be evaluated */
of COLS integers". It turns out that there is syntax which can int ncols = 10;
be used for this type /* or read in at run time */
without the need oftyp e d ef. If we write: int row;
int (*xptr)[COLS]; int **rowptr;
the variablexp t r will have all the same characteristics as the rowptr = malloc(nrows * sizeof(int *));
variablerp tr in METHOD if (rowptr == NULL)
1 above, and we need not use thetyp ed ef keyword. Herexp t {
r is a pointer to an array of puts("\nFailure to allocate room for row pointers.\n");
integers and the size of that array is given by the #defined exit(0);
COLS. The parenthesis }printf("\n\n\nIndex
placement makes the pointer notation predominate, even Pointer(hex)
though the array notation has Pointer(dec)
higher precedence. i.e. had we written Diff.(dec)");
for (row = 0; row < nrows; row++)
int *xptr[COLS];
we would have definedx p tr as an array of pointers holding rowptr[row] = malloc(ncols * sizeof(int));
the number of pointers equal to that #defined by COLS. That
if (rowptr[row] == NULL)
is not the same thing at all. However, arrays of pointers have
{
their use in the dynamic allocation of two dimensional arrays,
as will be seen in the next 2 methods. printf("\nFailure to allocate for row[%d]\n",row);
exit(0);
METHOD 3: }printf("\n%d
Consider the case where we do not know the number of %p
elements in each row at compile %d", row, rowptr[row],
time, i.e. both the number of rows and number of columns row]);
must be determined at run if (row > 0)
time. One way of doing this would be to create an array of printf("
pointers to typei nt and then
%d",(int)(rowptr[row] - rowptr[row-1]));
allocate space for each row and point these pointers at each
}return 0;
row. Consider: }--------------- End 9.2 ------------------------------------
-------------- Program 9.2 ------------------------------------ In the above coderow p t r is a pointer to pointer to typein t. In
/* Program 9.2 from PTRTUT10.HTM this case it points to the
6/13/97 */ first element of an array of pointers to typein t. Consider the
#include <stdio.h> number of calls tomal l oc():
#include <stdlib.h> To get the array of pointers
int main(void) 1
{ call
To get space for the rows
5 int **rptr;
calls int *aptr;
-----
int *testptr;
Total
6 int k;
calls int nrows = 5;
If you choose to use this approach note that while you can use /* Both nrows and ncols could be evaluated */
the array notation to access int ncols = 8;
/* or read in at run time */
individual elements of the array, e.g. rowptr[row][col] = 17;, it
does not mean that the
data in the "two dimensional array" is contiguous in memory. int row, col;
You can, however, use the array notation just as if it were a
continuous block of memory. /* we now allocate the memory for the array */
For example, you can write:
rowptr[row][col] = 176; aptr = malloc(nrows * ncols * sizeof(int));
just as if rowptr were the name of a two dimensional array if (aptr == NULL)
created at compile time. Of
courserow andcol must be within the bounds of the array you
puts("\nFailure to allocate room for the array");
have created, just as with
an array created at compile time. exit(0);
If you want to have a contiguous block of memory dedicated }/* next we allocate room for the pointers to the rows */
to the storage of the rptr = malloc(nrows * sizeof(int *));
elements in the array you can do it as follows: if (rptr == NULL)
METHOD 4: {
In this method we allocate a block of memory to hold the puts("\nFailure to allocate room for pointers");
whole array first. We then exit(0);
create an array of pointers to point to each row. Thus even }
though the array of pointers is * and now we 'point' the pointers */
being used, the actual array in memory is contiguous. The for (k = 0; k < nrows; k++)
code looks like this: {
rptr[k] = aptr + (k * ncols);
----------------- Program 9.3 -----------------------------------
}/* Now we illustrate how the row pointers are incremented */
/* Program 9.3 from PTRTUT10.HTM
printf("\n\nIllustrating how row pointers are incremented");
6/13/97 */
printf("\n\nIndex
#include <stdio.h>
Pointer(hex) Diff.(dec)");
#include <stdlib.h>
for (row = 0; row < nrows; row++)
int main(void)
{
printf("\n%d
%p", row, rptr[row]); Now, each call tomal l oc () creates additional space overhead
if (row > 0) sincemalloc( ) is generally
printf(" implemented by the operating system forming a linked list
%d",(rptr[row] - rptr[row-1])); which contains data
}printf("\n\nAnd now we print out the array\n"); concerning the size of the block. But, more importantly, with
for (row = 0; row < nrows; row++) large arrays (several
hundred rows) keeping track of what needs to be freed when
the time comes can be more
for (col = 0; col < ncols; col++) cumbersome. This, combined with the contiguousness of the
{ data block that permits
rptr[row][col] = row + col; initialization to all zeroes usingme mset () would seem to
printf("%d ", rptr[row][col]); make the second alternative the
}putchar('\n'); preferred one.
}puts("\n");
/* and here we illustrate that we are, in fact, dealing with As a final example on multidimensional arrays we will
a 2 dimensional array in a contiguous block of memory. */ illustrate the dynamic allocation
printf("And now we demonstrate that they are contiguous in of a three dimensional array. This example will illustrate one
memory\n"); more thing to watch when
doing this kind of allocation. For reasons cited above we will
testptr = aptr;
use the approach outlined in
for (row = 0; row < nrows; row++)
alternative two. Consider the following code:
{
------------------- Program 9.4 -------------------------------------
for (col = 0; col < ncols; col++)
/* Program 9.4 from PTRTUT10.HTM
{
6/13/97 */
printf("%d ", *(testptr++));
}putchar('\n'); #include <stdio.h>
}return 0; #include <stdlib.h>
}------------- End Program 9.3 ----------------- #include <stddef.h>
Consider again, the number of calls to malloc()
To get room for the array itself int X_DIM=16;
1 int Y_DIM=5;
call int Z_DIM=3;
To get room for the array of ptrs int main(void)
1
call
---- char *space;
Total char ***Arr3D;
2 int y, z;
calls ptrdiff_t diff;
40
/* first we set aside space for the array itself */ diff = Arr3D[z][y] - space;
printf("
space = malloc(X_DIM * Y_DIM * Z_DIM * sizeof(char)); diff = %d ",diff);
printf(" z = %d y = %d\n", z, y);
/* next we allocate space of an array of pointers, each }
to eventually point to the first element of a }return 0;
}------------------- End of Prog. 9.4 ----------------------------
If you have followed this tutorial up to this point you should
2 dimensional array of pointers to pointers */
have no problem
deciphering the above on the basis of the comments alone.
Arr3D = malloc(Z_DIM * sizeof(char **)); There are a couple of points
that should be made however. Let's start with the line which
/* and for each of these we assign a pointer to a newly reads:
allocated array of pointers to a row */ Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
for (z = 0; z < Z_DIM; z++)
{ Note that heresp ac e is a character pointer, which is the
Arr3D[z] = malloc(Y_DIM * sizeof(char *)); same type asA rr3 D[z] [y]. It is
important that when adding an integer, such as that obtained
and for each space in this array we put a pointer to
by evaluation of the
the first element of each row in the array space expression (z*(X_DIM * Y_DIM) + y*X_DIM), to a pointer, the
originally allocated */ result is a new pointer
41 value. And when assigning pointer values to pointer variables
for (y = 0; y < Y_DIM; y++) the data types of the value
{ and variable must match.
Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
} 42
}/* And, now we check each address in our 3D array to see if CHAPTER 10: Pointers to Functions
the indexing of the Arr3d pointer leads through in a Up to this point we have been discussing pointers to data
continuous manner */ objects. C also permits the
for (z = 0; z < Z_DIM; z++) declaration of pointers to functions. Pointers to functions have
a variety of uses and some
printf("Location of array %d is %p\n", z, *Arr3D[z]); of them will be discussed here.
for ( y = 0; y < Y_DIM; y++) Consider the following real problem. You want to write a
{ function that is capable of
printf(" Array %d and Row %d starts at %p", z, y, sorting virtually any collection of data that can be stored in an
array. This might be an
array of strings, or integers, or floats, or even structures. The
sorting algorithm can be the
same for all. For example, it could be a simple bubble sort printf("%d ", arr[i]);
algorithm, or the more }return 0;
complex shell or quick sort algorithm. We'll use a simple }void bubble(int a[], int N)
bubble sort for demonstration
purposes. int i, j, t;
Sedgewick [1] has described the bubble sort using C code by for (i = N-1; i >= 0; i--)
setting up a function which when passed a pointer to the {
array would sort it. If we call that functionb ub b le(), a sort for (j = 1; j <= i; j++)
program is described by bubble_1.c, which follows: 43
/*-------------------- bubble_1.c--------------------*/ {
/* Program bubble_1.c from PTRTUT10.HTM if (a[j-1] > a[j])
6/1 t = a[j-1];
a[j-1] = a[j];
3/97 */ a[j] = t;
}
#include <stdio.h> }
}
int arr[10] = { 3,6,1,2,3,8,4,1,7,2}; }/*---------------------- end bubble_1.c-----------------------*/
The bubble sort is one of the simpler sorts. The algorithm
void bubble(int a[], int N); scans the array from the second
to the last element comparing each element with the one
int main(void) which precedes it. If the one that
precedes it is larger than the current element, the two are
swapped so the larger one is
int i; closer to the end of the array. On the first pass, this results in
putchar('\n'); the largest element ending
for (i = 0; i < 10; i++) up at the end of the array. The array is now limited to all
{ elements except the last and the
printf("%d ", arr[i]); process repeated. This puts the next largest element at a
point preceding the largest
element. The process is repeated for a number of times equal
}bubble(arr,10);
to the number of elements
minus 1. The end result is a sorted array.
putchar('\n');
Here our function is designed to sort an array of integers.
for (i = 0; i < 10; i++) Thus in line 1 we are
comparing integers and in lines 2 through 4 we are using
{
temporary integer storage to
store integers. What we want to do now is see if we can }bubble(arr,10);
convert this code so we can use
any data type, i.e. not be restricted to integers. putchar('\n');
At the same time we don't want to have to analyze our
algorithm and the code associated for (i = 0; i < 10; i++)
with it each time we use it. We start by removing the {
comparison from within the printf("%d ", arr[i]);
functionb u b b le() so as to make it relatively easy to modify }return 0;
the comparison function }void bubble(int a[], int N)
without having to re-write portions related to the actual
algorithm. This results in
int i, j, t;
bubble_2.c:
for (i = N-1; i >= 0; i--)
/*---------------------- bubble_2.c-------------------------*/ {
/* Program bubble_2.c from PTRTUT10.HTM
6/13/97 */ for (j = 1; j <= i; j++)
{
if (compare(a[j-1], a[j]))
/* Separating the comparison function */
t = a[j-1];
#include <stdio.h>
a[j-1] = a[j];
a[j] = t;
int arr[10] = { 3,6,1,2,3,8,4,1,7,2};
}
}
void bubble(int a[], int N); }
int compare(int m, int n); }int compare(int m, int n)
int main(void) {
return (m > n);
}/*--------------------- end of bubble_2.c-----------------------*/
int i;
putchar('\n'); If our goal is to make our sort routine data type independent,
one way of doing this is to use pointers to type void to point
44
to the data instead of using the integer data type. As a start in
for (i = 0; i < 10; i++)
{ that direction let's modify a few things in the above so that
printf("%d ", arr[i]); pointers can be used. To begin with, we'll stick with pointers
to type integer.
/*----------------------- bubble_3.c-------------------------*/
/* Program bubble_3.c from PTRTUT10.HTM 6/13/97 */
#include <stdio.h>
int arr[10] = { 3,6,1,2,3,8,4,1,7,2}; to the data instead of using the integer data type. As a start in
void bubble(int *p, int N); that direction let's modify a few things in the above so that
int compare(int *m, int *n); pointers can be used. To begin with, we'll stick with pointers
int main(void) to type integer.
{
45 /*----------------------- bubble_3.c-------------------------*/
int i; /* Program bubble_3.c from PTRTUT10.HTM 13/97 */
putchar('\n'); #include <stdio.h>
for (i = 0; i < 10; i++) int arr[10] = { 3,6,1,2,3,8,4,1,7,2};
{ void bubble(int *p, int N);
printf("%d ", arr[i]); int compare(int *m, int *n);
}bubble(arr,10); int main(void)
putchar('\n'); {
for (i = 0; i < 10; i++) int i;
{ putchar('\n');
printf("%d ", arr[i]); for (i = 0; i < 10; i++)
}return 0; {
}void bubble(int *p, int N) printf("%d ", arr[i]);
int i, j, t; }bubble(arr,10);
for (i = N-1; i >= 0; i--)
{ putchar('\n');
for (j = 1; j <= i; j++)
{ for (i = 0; i < 10; i++)
if (compare(&p[j-1], &p[j])) {
printf("%d ", arr[i]);
}return 0;
t = p[j-1]; }void bubble(int *p, int N)
p[j-1] = p[j];
p[j] = t;
int i, j, t;
}
for (i = N-1; i >= 0; i--)
}
} {
}int compare(int m, int n) for (j = 1; j <= i; j++)
{
{ if (compare(&p[j-1], &p[j]))
return (m > n);
}/*--------------------- end of bubble_2.c-----------------------*/
t = p[j-1];
If our goal is to make our sort routine data type independent,
p[j-1] = p[j];
one way of doing this is to use pointers to type void to point
p[j] = t;
}
} }bubble(arr,10);
}
}int compare(int *m, int *n)
{ putchar('\n');
return (*m > *n);
}/*------------------ end of bubble3.c-------------------------*/ for (i = 0; i < 10; i++)
Note the changes. We are now passing a pointer to an integer {
(or array of integers) to printf("%d ", arr[i]);
bubble(). And from within bubble we are passing pointers to }return 0;
the elements of the array }void bubble(int *p, int N)
that we want to compare to our comparison function. And, of
course we are dereferencing int i, j, t;
these pointer in ourco m p are() function in order to make the for (i = N-1; i >= 0; i--)
actual comparison. Our next {
step will be to convert the pointers inb u b b le() to pointers to
type void so that that for (j = 1; j <= i; j++)
{
function will become more type insensitive. This is shown in
if (compare((void *)&p[j-1], (void *)&p[j]))
bubble_4.
/*------------------ bubble_4.c----------------------------*/
/* Program bubble_4.c from PTRTUT10,HTM t = p[j-1];
6/13/97 */ p[j-1] = p[j];
#include <stdio.h> p[j] = t;
}
}
}
int arr[10] = { 3,6,1,2,3,8,4,1,7,2}; }int compare(void *m, void *n)
void bubble(int *p, int N);
int compare(void *m, void *n); int *m1, *n1;
int main(void) m1 = (int *)m;
n1 = (int *)n;
int i; return (*m1 > *n1);
putchar('\n'); }/*------------------ end of bubble_4.c---------------------*/
for (i = 0; i < 10; i++) Note that, in doing this, inco mp are( ) we had to introduce
{ the casting of the void pointer types passed to the actual type
printf("%d ", arr[i]);
being sorted. But, as we'll see later that's okay. And since
what is being passed tob u b b le() is still a pointer to an array
of integers, we had to cast these pointers to void pointers int compare(void *m, void *n);
when we passed them as parameters in our call to int main(void)
compare().
We now address the problem of what we pass tob u b b le(). int i;
We want to make the first putchar('\n');
parameter of that function a void pointer also. But, that for (i = 0; i < 10; i++)
means that withinb u b b le() we {
need to do something about the variablet, which is currently printf("%d ", arr[i]);
an integer. Also, where we
use t = p[j-1]; the type ofp [j-1] needs to be known in order to }bubble(arr, sizeof(long), 10);
know how many bytes to
copy to the variablet (or whatever we replacet with). putchar('\n');
Currently, in bubble_4.c, knowledge withinb u b b le() as to
the type of the data being for (i = 0; i < 10; i++)
sorted (and hence the size of each individual element) is {
obtained from the fact that the printf("%ld ", arr[i]);
first parameter is a pointer to type integer. If we are going to }return 0;
be able to useb u bb le() to }void bubble(void *p, size_t width, int N)
sort any type of data, we need to make that pointer a pointer
to typevoid. But, in doing so
int i, j;
we are going to lose information concerning the size of
unsigned char buf[4];
individual elements within the
unsigned char *bp = p;
array. So, in bubble_5.c we will add a separate parameter to
handle this size information. for (i = N-1; i >= 0; i--)
These changes, from bubble4.c to bubble5.c are, perhaps, a
bit more extensive than those for (j = 1; j <= i; j++)
we have made in the past. So, compare the two modules {
carefully for differences.
/*---------------------- bubble5.c---------------------------*/ if (compare((void *)(bp + width*(j-1)),
/* Program bubble_5.c from PTRTUT10.HTM (void *)(bp + j*width))) /* 1 */
6/13/97 */ {
#include <stdio.h> /*
t = p[j-1];
*/
#include <string.h> memcpy(buf, bp + width*(j-1), width);
/*
long arr[10] = { 3,6,1,2,3,8,4,1,7,2}; p[j-1] = p[j];
*/
memcpy(bp + width*(j-1), bp + j*width , width);
void bubble(void *p, size_t width, int N);
/* comparison function since the means by which strings are
p[j] = t; compared is different from that
*/ by which long integers are compared. And,in bubble6.c we
memcpy(bp + j*width, buf, width); have deleted the lines within
}
} bubble() that were commented out in bubble5.c.
} /*--------------------- bubble6.c---------------------*/
}int compare(void *m, void *n) /* Program bubble_6.c from PTRTUT10.HTM
6/13/97 */
49
long *m1, *n1; #include <stdio.h>
m1 = (long *)m; #include <string.h>
n1 = (long *)n; #define MAX_BUF 256
return (*m1 > *n1); arr2[5][20] = { "Mickey Mouse",
}/*--------------------- end of bubble5.c---------------------*/ "Donald Duck",
Note that I have changed the data type of the array fromin t "Minnie Mouse",
tolon g to illustrate the "Goofy",
changes needed in theco mp ar e() function. Withinb u bb le() "Ted Jensen" };
I've done away with the void bubble(void *p, int width, int N);
variablet (which we would have had to change from typein t int compare(void *m, void *n);
to typelon g). I have added int main(void)
a buffer of size 4 unsigned characters, which is the size
needed to hold a long (this will int i;
change again in future modifications to this code). The putchar('\n');
unsigned character pointer*b p is
for (i = 0; i < 5; i++)
used to point to the base of the array to be sorted, i.e. to the
{
first element of that array. printf("%s\n", arr2[i]);
We also had to modify what we passed toco mp ar e(), and
how we do the swapping of elements that the comparison
}bubble(arr2, 20, 5);
indicates need swapping. Use ofme mcp y() and pointer
notation instead of array notation work towards this reduction
in type sensitivity. putchar('\n\n');
int i;
memcpy(buf, bp + width*(j-1), width);
puts("\nBefore Sorting:\n");
memcpy(bp + width*(j-1), bp + j*width , width);
for (i = 0; i < 10; i++)
memcpy(bp + j*width, buf, width);
/* show the long ints */
{ }
printf("%ld ",arr[i]); }
}puts("\n"); }
for (i = 0; i < 5; i++) }int compare_string(const void *m, const void *n)
/* show the strings */
{
char *m1 = (char *)m;
printf("%s\n", arr2[i]);
}bubble(arr, 4, 10, compare_long); char *n1 = (char *)n;
/* sort the longs */ return (strcmp(m1,n1));
bubble(arr2, 20, 5, compare_string); }int compare_long(const void *m, const void *n)
/* sort the strings */
puts("\n\nAfter Sorting:\n");
for (i = 0; i < 10; i++) long *m1, *n1;
/* show the sorted longs */ m1 = (long *)m;
{ n1 = (long *)n;
printf("%d ",arr[i]); return (*m1 > *n1);
}puts("\n");
}/*----------------- end of bubble7.c-----------------*/
for (i = 0; i < 5; i++)
References for Chapter 10:
/* show the sorted strings */
{ 1. "Algorithms in C"
printf("%s\n", arr2[i]); Robert Sedgewick
}return 0; Addison-Wesley
}void bubble(void *p, int width, int N, ISBN 0-201-51425-7
int(*fptr)(const void *, const void *))
EPILOG
I have written the preceding material to provide an
int i, j, k;
introduction to pointers for
unsigned char buf[MAX_BUF];
newcomers to C. In C, the more one understands about
unsigned char *bp = p; pointers the greater flexibility one
for (i = N-1; i >= 0; i--) has in the writing of code. The above expands on my first
effort at this which was entitled
ptr_help.txt and found in an early version of Bob Stout's
collection of C code SNIPPETS.
The content in this version has been updated from that in
PTRTUTOT.ZIP included in
SNIP9510.ZIP.
I am always ready to accept constructive criticism on this
material, or review requests for
the addition of other relevant material. Therefore, if you have
questions, comments,
criticisms, etc. concerning that which has been presented, I
would greatly appreciate your
contacting me via email me attjen sen @i x.n etco m. co m.