Physics and Astronomy |
Back to top
Appendix: pointers and string traversalThe occasional appendices and optional examples in this module are for advanced material that you will not need for this module. They are intended for enthusiastic students who are interested in going further in programming for its own sake. This appendix describes a more "bare metal" way of traversing arrays which is often used when looking at character strings. Passing pointers to strings (and other arrays) to functionsWe remind ourselves that the name of an array is a synonym for the address of its first element. #include <stdio.h> #include <string.h> void printstr(const char tmp[]); main() { char str[] = "abcdxyz"; printstr(str); strcpy(str, "Hi!"); printstr(str); } void printstr(const char tmp[]) { int i; for(i = 0; tmp[i] != '\0'; ++i) putchar(tmp[i]); putchar('\n'); } The first line of main both declares and initialises str. The empty brackets [] tell the compiler to make the array equal to the size of the string (ie 8, the number of characters plus one for the final zero).
The pointer to the start of the string is then passed to printstr which goes over the string printing out each character in turn until it comes to the end. We could have just written the test part
of the for loop as just "tmp[i]",
rather than "tmp[i] != '\0'"
This is
because
a 'logical' test is just an integer value which is considered to
be 'true' if that value is non-zero and
Strings are
terminated with a binary zero (often written '\0'
The canonical parameter declarationWe recall that the parameter declaration of tmp in: void printstr(const char tmp[]); does not create a new character array but a variable whose value is the start of a constant character array (that is to say, tmp points to an array of characters that the function guarrentees not to change): As a convenience to the programmer, when a function expects to be passed the address of the first element of an array the corresponding parameter can just be declared with the same declaration as the passed array with the left-hand dimension being ignored. Thus the true, canonical declaration for printstr() would be: void printstr(const char *tmp); Changing the value of the local pointer variableAlthough the above version of printstr() is the most intuitive, a popular idiom is to increment the local pointer variable:
In an argument list the two constructs
char tmp[]
and
char *tmp mean the same thing.
This is because they both say "this is the start of
an array which has been defined somewhere else."
void printstr(const char *tmp) { for(; *tmp; ++tmp) putchar(*tmp); putchar('\n'); } The argument is still a copy of the originalThe loop in this version of printstr looks strange because we are changing tmp. But remember, tmp is a variable just like any other. Let's assume that the string pointed to by str starts at memory location 400: ----------------------------------------------- Byte number: | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | ----------------------------------------------- Value: | 'a' | 'b' | 'c' | 'e' | 'x' | 'y' | 'z' | \0 | -----------------------------------------------(Remember, each printable character from the 'normal' latin alphabet is assigned an integer value in the range 1-127 which is the value actually stored in the computer's memory.) When we call printstr then tmp is given its own (temporary) piece of memory to store its value (say bytes 640-643) and that value is initialised to 400: ------------------------ Byte number: | 640 | 641 | 642 | 643 | ----------------------- Value: | 400 | ----------------------- <- tmp (in printstr) ->As we keep adding one to tmp it has the values 401, 402, etc until it reaches 407 and it stops because *407 is zero. Then when printstr returns the memory at location 640 is freed and is available for use by variables as other functions are called and so the changes make to tmp are lost. |