There is a very close relationship between pointer and array notation in C. As we have seen already the name of an array ( or string ) is actually the address in memory of the array and so it is essentially a constant pointer.
For Example :-
char str[80], *ptr ; ptr = str ;/* causes ptr to point to start of string str */ ptr = &str[0] ; /* this performs the same as above */
It is illegal however to do the following str = ptr ; /* illegal */
as str is a constant pointer and so its value i.e. the address it holds cannot be changed.
Instead of using the normal method of accessing array elements using an index we can use pointers in much the same way to access them as follows.
char str[80], *ptr , ch; ptr = str ; // position the pointer appropriately *ptr = 'a' ; // access first element i.e. str[0] ch = *( ptr + 1 ) ; // access second element i.e. str[1] Thus *( array + index ) is equivalent to array[index].
Note that the parentheses are necessary above as the precedence of * is higher than that of +. The expression
ch = *ptr + 1;
for example says to access the character pointed to by ptr ( str[0] in above example with value ‘a’) and to add the value 1 to it. This causes the ASCII value of ‘a’ to be incremented by 1 so that the value assigned to the variable ch is ‘b’.
In fact so close is the relationship between the two forms that we can do the following
int x[10], *ptr ; ptr = x ; ptr[4] = 10 ; /* accesses element 5 of array by indexing a pointer */
Pointer variables can be manipulated in certain limited ways. Many of the manipulations are most useful when dealing with arrays which are stored in contiguous memory locations. Knowing the layout of memory enables us to traverse it using a pointer and not get completely lost.
• Assignment
int count, *p1, *p2 ;
p1 = &count ; // assign the address of a variable directly
p2 = p1 ; // assign the value of another pointer variable, an address
•Addition / Subtraction
The value a pointer holds is just the address of a variable in memory, which is normally a four byte entity. It is possible to modify this address by integer addition and subtraction if necessary. Consider the following we assume a 32-bit system and hence 32-bit integers.
int *ptr ; int array[3] = { 100, 101, 102 } ; ptr = array ;
We now have the pointer variable ptr pointing at the start of array which is stored at memory location 2008 in our illustration. Since we know that element array[1] is stored at address 2012 directly after element array[0] we could perform the following to access its value using the pointer.
ptr += 1 ;
This surprisingly will cause ptr to hold the value 1012 which is the address of array[1], so we can access the value of element array[1]. The reason for this is that ptr is defined to be a pointer to type int, which are four bytes in size on a 32-bit system. When we add 1 to ptr what we want to happen is to point to the next integer in memory. Since an integer requires four bytes of storage the compiler increments ptr by 4. Likewise a pointer to type char would be incremented by 1, a pointer to float by 4, etc.
Similarly we can carry out integer subtraction to move the pointer backwards in memory.
ptr = ptr - 1 ; ptr -= 10 ;
The shorthand operators ++ and -- can also be used with pointers. In our continuing example with integers the statement ptr++ ; will cause the address in ptr to be incremented by 4 and so point to the next integer in memory and similarly ptr-- ; will cause the address in ptr to be decremented by 4 and point to the previous integer in memory.
NOTE : Two pointer variables may not be added together ( it does not make any logical sense ).
char *p1, *p2 ; p1 = p1 + p2 ; /* illegal operation */
Two pointers may however be subtracted as follows.
int *p1, *p2, array[3], count ; p1 = array ; p2 = &array[2] ; count = p2 - p1 ; /* legal */
The result of such an operation is not however a pointer, it is the number of elements of the base type of the pointer that lie between the two pointers in memory.
We can compare pointers using the relational operators ==, <, and > to establish whether two pointers point to the same location, to a lower location in memory, or to a higher location in memory. These operations are again used in conjunction with arrays when dealing with sorting algorithms etc.
For Example :- Writing our own version of the puts() standard library function.
1. Using array notation
void puts( const char s[ ] ) /* const keyword makes string contents read only */ { int i ; for ( i = 0; s[i] ; i++ ) putchar( s[i] ) ; putchar( ' ' ) ; }
2. Using pointer notation
void puts( const char *s ) // char *const s would make pointer unalterable { while ( *s ) putchar( *s++ ) ; putchar( ' ' ) ; }
As you can see by comparing the two versions above the second version using pointers is a much simpler version of the function. No extra variables are required and it is more efficient as we will see because of its use of pointer indirection.
For Example :- Palindrome program using pointers.
#include <stdio.h> int palin( char * ) ; /* Function to determine if array is a palindrome. returns 1 if it is a palindrome, 0 otherwise */ void main( ) { char str[30], c ; puts( "Enter test string" ) ; gets( str ) ; if ( palin( str ) ) printf( "%s is a palindrome\n", str ) ; else printf( "%s is not a palindrome\n") ; } int palin ( char *str ) { char *ptr ; ptr = str ; while ( *ptr ) ptr++ ; /* get length of string i.e. increment ptr while *ptr != "\0" */ ptr-- ; /* move back one from "\0"*/ while ( str < ptr ) if ( *str++ != *ptr-- ) return 0 ; /* return value 0 if not a palindrome */ return 1 ; /* otherwise it is a palindrome */ }
C's standard library string handling functions use pointers to manipulate the strings. For example the prototype for the strcmp() function found in <string.h> is
int strcmp( const char *string1, const char *string2 ) ;
where const is a C keyword which locks the variable it is associated with and prevents any inadvertent changes to it within the function.
Strings can be initialised using pointer or array notation as follows
char *str = "Hello\n" ; char string[] = "Hello\n" ;
in both cases the compiler allocates just sufficient storage for both strings.
It is possible to declare arrays of pointers in C the same as any other 'type'. For example
int *x[10] ;
declares an array of ten integer pointers.
To make one of the pointers point to a variable one might do the following.
x[ 2 ] = &var ;
To access the value pointed to by x[ 2 ] we would do the following
*x[ 2 ]
which simply de-references the pointer x[ 2 ] using the * operator.
Passing this array to a function can be done by treating it the same as a normal array which happens to be an array of elements of type int *.
For Example : -
void display( int *q[ ], int size ) { int t ; for ( t=0; t < size; t++ ) printf( "%d ", *q[t] ) ; }
Note that q is actually a pointer to an array of pointers as we will see later on with multiple indirection.
A common use of pointer arrays is to hold arrays of strings.
For Example :- A function to print error messages.
void serror( int num ) { static char *err[] = { "Cannot Open File\n", "Read Error\n", "Write Error\n" } ; puts( err[num] ); }
Note that using an array of pointers to char initialised as above conserves space as no blank filling characters are required as would be if we used
char err[3][30] = { ... } ;
Command line arguments allow us to pass information into the program as it is run. For example the simple operating system command type uses command line arguments as follows
c:>type text.dat
where the name of the file to be printed is taken into the type program and the contents of the file then printed out.
In C there are two in-built arguments to the main() function commonly called argc and argv which are used to process command line arguments.
void main( int argc, char *argv[ ] ) { ... }
argc is used to hold the total number of arguments used on the command line which is always at least one because the program name is considered the first command line argument.
argv is a pointer to an array of pointers to strings where each element in argv points to a command line argument. For example argv[0] points to the first string, the program name.
For Example :- Program to print a name ( saved in name.c ) using command line arguments.
#include <stdio.h> void main( int argc, char *argv[ ] ) { if ( argc != 2 ) { puts( "Missing parameter. Usage : name yourname" ) ; exit( 1 ); } printf( "Hello %s", argv[1] ) ; }
To run the program one might type
c:\>name tom
For Example :- Program to count down from a given value, the countdown being displayed if the argument "display" is given.
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> void main( int argc, char *argv[ ] ) { int disp, count ; if ( argc < 2 ) { puts("Missing Arguments Usage : progname count [display]" ); exit(1) ; } if ( argc > 2 && !strcmp( argv[2], "display" ) ) disp = 1 ; else disp = 0 ; for ( count = atoi( argv[1] ) ; count ; count-- ) if ( disp ) printf( "%d\n", count ) ; printf( “done\n” ) ; }
NOTE : C has a broad range of functions to convert strings into the standard data types and vice versa. For example atoi() converts a string to an integer above - remember all command line arguments are just character strings.
All Rights Reserved. © 2024 BookOfNetwork