Last updated: July 1, 2021
 
red bullet point Home
red bullet point Grant
red bullet point Objective
red bullet point Strategy
red bullet point Timeline
red bullet point Project Team
red bullet point Technician
red bullet point Hardware
red bullet point Software
red bullet point Account
red bullet point Teaching Material
red bullet point Course / Lab
red bullet point Research
red bullet point Resource
red bullet point FAQ
red bullet point Vacancy
 
arrow HPCCC Website
 
Total Visitors since
28 Aug 2003: 424794
 
Valid XHTML 1.0!
 
Valid CSS!
Click here to download the PDF version

Chapter 7: Pointers
===================
* Pointers are variables that contain memory addresses as their
values.
* A variable name directly references a value
* A pointer indirectly references a value.

countPtr count
+-----+ +-----+
|213f-+------------->| 7 |
+-----+ +-----+
0176 213f

* The declaration:
int *countPtr, count;
* The "*" only applies to "countPtr" in the declaration, it indicates
that the variable being declared is a pointer.
* Pointers can be declared to point to objects of any data type
(including user-defined).

* A pointer may be initialized to "0", "NULL", or an address.
* A pointer with the value "NULL" points to nothing.
* The value "0" is the only integer value that can be assigned
directly to a pointer variable.

Pointer Operators
-----------------
* The "&", or address operator, is a unary operator that returns the
address of its operand.
* E.g.
int y = 5;
int *yPtr;
....
yPtr = &y;
....
* This statement assigns the adress of the variable "y" to pointer
variable "yPtr".
* The operand of the address operator must be a variable; it cannot
be constants, expressions, or variables declared with the storage
class "register".

* The "*" operator, commonly referred to as the indirection operator
or dereferencing operator, returns the value of the object to which
its operand (i.e., a pointer) points.
* E.g.
printf("%d", *yPtr);

Calling Functions by Address
----------------------------
* All function calls in C are call by value.
* Many functions require the capability to
1. modify one or more variables in the caller
2. pass a pointer to a large data object to avoid the overhead of
passing the object call by value (which requires making a copy of
the object).
* In C, when calling a function with arguments that should be
modified, the addresses of the arguments are passed.
* When the address of a variable is passed to a function, the
indirection operator ("*") may be used in the function to modify the
value at that location in the caller's memory.
* E.g.
#include <stdio.h>
int cubeByValue(int);
main()
{
int number = 5;

printf("The original value of number is %d\n", number);
number = cubeByValue(number);
printf("The new value of number is %d\n", number);
return 0;
}

int cubeByValue(int n)
{
return n * n * n;
}
* E.g.
#include <stdio.h>
int cubeByReference(int *);
main()
{
int number = 5;

printf("The original value of number is %d\n", number);
cubeByReference(&number);
printf("The new value of number is %d\n", number);
return 0;
}

int cubeByReference(int *nPtr)
{
*nPtr = (*nPtr) * (*nPtr) * (*nPtr);
}

* The compiler does not differentiate between a function that
receives a pointer and a function that receives a single-subscripted
array.
* That is, the following two forms are (almost) the same,
int cubeByReference(int *nPtr)
{
.....
}
And
int cubeByReference(int nPtr[])
{
.....
}

Using the "Const" Qualifier with Pointers
=========================================
* The "const" qualifier enables the programmer to inform the compiler
that the value of a particular variable should not be modified.
* Always award a function enough access to the data in its parameters
to accomplish its specified task, but no more.

* An array name is a constant pointer to the beginning of the array.
* All data in the array can be accessed and changed by using the
array name and array index.
* E.g.
char string[] = "characters";
char character = 'C';
....
string = &character; /* error */
....
* Pointers that are declared "const" must be initialized when they
are declared.
* A constant pointer:
char string[] = "characters";
* A non-constant pointer to a contant data:
const char *string;
* A constant pointer to non-constant data:
int * const ptr = &x;
* A constant pointer to a constant data:
const int *const ptr = &x;

"sizeof" operator
-----------------
* C provides the special unary operator "sizeof" to determine the
size in bytes of an array (or any other data type) during program
compilation.
* E.g.
#include <stdio.h>
main()
{
float array[20];
printf("The number of bytes in the array is %d\n",
sizeof(array));
return 0;
}
* To determine the number of elements in the array,
arraysize = sizeof(array) / sizeof(double);
* Operator "sizeof" can be applied to any variable name, type, or
constant.
* When applied to a variable name (that is not an array name) or a
constant, the number of bytes used to store the specific type of
variable or constant is found.
* E.g.
#include <stdio.h>
main()
{
printf(" sizeof(char) = %d\n"
" sizeof(short) = %d\n"
" sizeof(int) = %d\n"
" sizeof(long) = %d\n"
" sizeof(float) = %d\n"
" sizeof(double) = %d\n"
" sizeof(long double) = %d\n",
sizeof(char), sizeof(short), sizeof(int),
sizeof(long), sizeof(float), sizeof(double),
sizeof(long double));
return 0;
}

Pointer Expressions and Pointer Arithmetic
------------------------------------------
* Pointers can be valid operands in arithmetic expressions,
assignment expressions, and comparison expressions.
* A pointer may be
1. incremented (++)
2. decremented (--)
3. an integer adds to a pointer (+ or +=)
4. an integer substracts from a pointer (- or -=)
5. one pointer substracts from another
* When an integer is added to (or substracted from) a pointer, the
pointer is not simply incremented (or decremented) by the integer,
but by that integer times the size of the object to which the pointer
refers.
* Therefore,
a = v[20];
and
a = *(v+20);
is the same, no matter what the type of array "v" is.
* Pointer arithmetic is meaningless unless performed on an array.

* A pointer can be assigned to another pointer if both pointers are
of the same type.
* Otherwise, a cast operator must be used to convert the pointer on
the right of the assignment to the pointer type on the left of the
assignment.
* The exeception to this rule is the pointer to "void" (i.e.,
"void *") which is a generic pointer that can represent any pointer
type.
* A pointer to "void" cannot be dereferenced.

* Pointers can be compared using equality and relational operators.
* This can be meaningless unless the pointers point to members of the
same array.

The Relationship between Pointers and Arrays
--------------------------------------------
* An array name can be thought of as a constant pointer.
* Pointers can be used to do any operation involving array indexing.
* E.g.
int b[5], *bPtr;
....
bPtr = b; /* or bPtr = &b[0]; */
....
b[3] = 10; /* or *(bPtr + 3) = 10; */
/* or *(b + 3) = 10; */
....
bPtr[1] = 2; /* or b[1] = 2; */
/* or *(bPtr + 1) = 2; */
....
bPtr = &b[3]; /* or bPtr = bPtr + 3; */
....
* Question: Then "bPtr[1]" = ??
* The "3" in the above expression is the offset to the pointer.
* When the pointer points to the beginning of an array, the offset
value is identical to the array index.
* E.g.
#include <stdio.h>
main()
{
int i, offset, b[]={10,20,30,40};
int *bPtr = b;

printf("Array b printed with:\n"
"Array indexing notation\n");
for (i=0; i<4; i++)
printf("b[%d] = %d\n", i, b[i]);

printf("\nPointer/offset notation where \n"
"the pointer is the array name\n");
for (offset=0; offset<4; offset++)
printf("*(b + %d) = %d\n", offset, *(b+offset));

printf("\nPointer index notation\n");
for (i=0; i<4; i++)
printf("bPtr[%d] = %d\n", i, bPtr[i]);

printf("\nPointer/offset notation\n");
for (offset=0; offset<4; offset++)
printf("*(bPtr + %d) = %d\n", offset,
*(bPtr+offset));
return 0;
}
* E.g.
#include <stdio.h>
void copy1(char *, const char *);
void copy2(char *, const char *);
main()
{
char string1[10], *string2 = "Hello";
string3[10], string4[] = "Good Bye";

copy1(string1, string2);
printf("string1 = %s\n", string1);

copy2(string3, string4);
printf("string3 = %s\n", string3);
return 0;
}

void copy1(char *s1, const char *s2)
{
int i;
for (i=0; s1[i] = s2[i]; i++);
}

void copy2(char *s1, const char *s2)
{
for (; *s1 = *s2; s1++, s2++);
}

Arrays of Pointers
------------------
* Arrays may contain pointers.
* A common use of such a data structure is to form an array of
strings.
* Each entry in an array of strings is actually a pointer to the
first character of a string.
* E.g.
char *suit[4] = {"Hearts", "Diamonds", "Clubs", "Spades"};
* Each of these strings is stored in memory as a NULL-terminated
character string.
* Although it appears as though these strings are being placed in the
"suit" array, only pointers are actually stored in the array.
* Thus, even though the "suit" array is fixed in size, it provides
access to character strings of any length.
* E.g.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void shuffle(int [][13]);
void deal(const int [][13], const char *[], const char *[]);

main()
{
char *suit[4] = {"Hearts", "Diamonds", "Clubs",
"Spades"};
char *face[13] = {"Ace", "Deuce", "Three", "Four",
"Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Jack", "Queen",
"King"};
int deck[4][13] = {0};

srand(time(NULL));
shuffle(deck);
deal(deck, face, suit);
return 0;
}

void shuffle(int wDeck[][13])
{
int card, row, column;

for (card=1; card<=52; card++)
{
row = rand() % 4;
column = rand() % 13;
while (wDeck[row][column]!=0)
{
row = rand() % 4;
column = rand() % 13;
}
wDeck[row][column] = card;
}
}

void deal(const int wDeck[][13], const char *wFace[],
const char *wSuit[])
{
int card, row, column;
for (card=1; card<=52; card++)
for (row=0; row<4; row++)
for (column=0; column<13; column++)
if (wDeck[row][column] == card)
printf("%5s of %-8s%c",
wFace[column], wSuit[row],
(card%2)==0?'\n':'\t');
}

Pointer to Functions
--------------------
* A pointer to a function contains the address of the function in
memory.
* A function name is the starting address in memory of the code that
performs the function's task.
* Pointers to functions can be
1. passed to functions
2. returned from functions
3. stored in arrays
4. assigned to other function pointers
* E.g.
void bubble(int *work, const int size,
int (*compare)(int, int))
{
......
if ((*compare)(work[count], work[count+1]))
......

}
* The parameter:
int (*compare)(int, int)
tells "bubble" to expect a parameter that is a pointer to a function
that receives two integer parameters and returns an integer result.



©2002-2024 Hong Kong Baptist University. All Rights Reserved.