SIPB’s IAP Programming in C
Pointers, and Arrays
Memory and Addresses stack stack grows down - C programs exist inside a memory space (unmapped) - That memory space is a sequence of bytes heap grows heap up - Each of those bytes has an address bss text
Addresses and Pointers stack - Addresses are usually represented in hexadecimal (unmapped) - A pointer is a 0x6f80a2e0 variable, whose value x heap is an address - A pointer has an bss associated type, while an address does not text int *xPtr = &x;
Declaring a Pointer - Specify the type in the normal way /* point to a 32-bit integer */ int *xPtr; - Then, add an asterisk /* point to a 32-bit float */ float *fPtr; for each layer of /* point to an 8-bit integer */ pointing char *cPtr; /* point to a point to an int */ - Pointers to pointers int **xPtrPtr; are possible!
Assigning a Pointer - Pointers have a type int x; int *xPtr; - And that type needs /* ... */ to match up, during xPtr = &x; assignment
& int is_square(int square, int *rootPtr) &varName returns { /* ... */ address of varName } main() Works for local & { int square,root; global variables, array int *rootPtr; elements, and struct square = 25; rootPtr = &root; members if(is_square(square,rootPtr)) printf("%d is square, with " "root %d\n", That address can then square,root); else be stashed in a pointer printf("%d is NOT a square\n", square); }
* The asterisk derefer- ences a pointer: int is_square(int square, int *rootPtr) { - *Ptr evaluates to int i; for(i=0;;i++) { the value pointed to int i2 = i * i; by Ptr if(i2 == square) { if(rootPtr != NULL) *rootPtr = i; - Works for both return(1); right & left side of } else if(i2 > square) assignment return(0); } } - Can be nested
Asterisk vs. Ampersand int x,y; int *xPtr; - * is the inverse of & x = 22; - But only to a limited /* this: */ xPtr = &x; extent! y = *xPtr; /* is the same as - E.g. &*x is complete * this: */ y = *&x; hooey /* is the same as * this: */ y = x;
Multiple Pointers, Same Address - Multiple pointers can int x; int *xPtr,*yPtr; provide access to the yPtr = xPtr = &x; same underlying *xPtr = 22; value /* this will print: * *yPtr = 22 */ - Just set them all to printf("*yPtr = %d\n", the same address! *yPtr);
Call By Value - C’s calling convention includes calling by /* the concept of futility, value * expressed in C */ void swap(int a, - The parameter values int b) { are passed, not their int temp; address temp = a; a = b; b = temp; - Ergo, they are local to } the called function
Call By Reference - You can explicitly call by reference /* so much better */ void swap(int *a, - Reference being int *b) { another way to say int temp; address temp = *a; *a = *b; *b = temp; - And addresses, that } means pointers
Returning Values Via Pointers - Caller generates pointers to local - On return, caller variables finds local variables - Callee takes those set to new values pointers as - And to the next arguments slide, for the - Callee writes values example through those pointers
Just Like Magic int is_square(int square, int *rootPtr) main() { { int i; int square,root; int *rootPtr; for(i=0;;i++) { int i2 = i * i; square = 25; rootPtr = &root; if(i2 == square) { if(rootPtr != NULL) if(is_square(22,rootPtr)) *rootPtr = i; printf("%d is a square, with " "root %d\n", return(1); square,root); } else else if(i2 > square) printf("%d is NOT a square\n", return(0); square); } } }
Arrays Array declarations are very similar to pointer declarations. /* these are identical */ int *xPtr; int xArr[]; - Array declarations /* this will allocate often allocate the * memory for the array */ int *yPtr; underlying values int yArr[10]; /* totally valid */ - In those cases, the yPtr = yArr; array pointer will be initialized accordingly
Pointer Arithmetic - Each pointer has a type, from which its size can be derived - This size is used by int *yPtr; int yArr[10]; the compiler, when yPtr = yArr; performing pointer /* these are the same! */ arithmetic yArr[3] = 1; *(yPtr + 3) = 1; - Pointer arithmetic and array indexing are identical
Pointer arithmetic, and array indexing Pointers are byte addresses (on most machines). Incrementing a char* pointer by one points it to the next byte. char int 0 1 2 3 4 5 6 7 8 If the pointer type is struct 0 1 2 larger, incrementing by element .x .y .c .x .y .c .x .y .c one will change the address by the number of bytes required to hold that type.
Arrays and Addresses - You can derive the address of an array int *yPtr,*y3Ptr; int yArr[10]; element yPtr = yArr; - And not suprisingly, /* these are the same! */ y3Ptr = &yArr[3]; this is closely related y3Ptr = yPtr + 3; to pointer arithmetic
sizeof() int *yPtr; int yArr[10]; The size of a given type /* what will this output or variable is available * look like? */ via the built-in function printf("sizeof(int) = %d\n" "sizeof(yPtr) = %d\n" sizeof() "sizeof(yArr) = %d\n", sizeof(int), sizeof(yPtr), sizeof(yArr));
-> The arrow dereferences a struct MyStruct { pointer to a structure int a; int b; element }; main() - Simultaneous { struct MyStruct m,*mPtr; structure member and m.a = 1; pointer dereference m.b = -1; mPtr = &m; - stPtr->x returns value printf("m.a = %d\n" "m.b = %d\n", of field x, of the struct mPtr->a, mPtr->b); pointed to by stPtr }
Strings Are Pointers Strings are not special. - A "char *" is a pointer to a block of memory - End of string is indicated by ’\0’ char *str = "This is a string"; character - Strings usually manipulation via library routines T h i s i s a s t r i n g \0
Strings Are Arrays int n = 1; char str[] = "This is a string"; printf("Character %d\n" "of ’%s’\n" "is ’%c’\n", We can use array n, str, notation, when str[n]); accessing strings. /* outputs: Character 1 of ’This is a string’ is ’h’ */ T h i s i s a s t r i n g \0
String Layout int strlen(char *s) { int i; for(i=0;s[i] != ’\0’;i++) - Strings are zero ; indexed return(i); } - I.e. the first character main() { is the zeroth char *s = "This is a string"; printf("strlen(s) = %d\n", - Strings are strlen(s)); } terminated with ’\0’ /* outputs: strlen(s) = 16 */ T h i s i s a s t r i n g \0
Casting Between Pointers - A cast will force conversion between types - A cast is a unary int *xPtr; operator char x[4]; xPtr = (int *)x; - A cast is written as a *xPtr = 22; type, between parans - E.g. (int), (double), (char *)
Pointers and Longs - Pointers have a size, which is architecture specific - This size is the native word size int x, *xPtr; - Longs are also native long p; words! xPtr = &x; p = (long)xPtr; - Longs and pointers can be cast back and forth - Not that you want to do that
Memory Allocation - Local variables allocated on the void *malloc(int count); stack void free(void *alloc); main() { - Most other int *xPtr; allocations are done xPtr = malloc(sizeof(int)); on the heap /* use xPtr here */ free(xPtr); - Standard libc way: } malloc() and free()
Heap Vs. Stack - Memory must be allocated and freed - On the stack: allocated and freed /* these variables are allocated * on the stack */ automatically in int i; function scope int *xPtr; char str200[200]; - On the heap: allocated /* this is allocated in * the heap */ and freed explicitly xPtr = (int *)malloc(sizeof(int)); - Don’t expect these allocations to be initialized
The Heap Is All Crazy - A memory allocator keeps track of which memory is in use - libc’s malloc is just a memory allocator heap - Complex systems often have their own allocators - Convention: unused text (your code) memory is kept on a "freelist"
Pointers are Power - There are no runtime safety checks - You can read & write memory anywhere the CPU can /* pointer casts like this can * really harsh the mellow */ - Typical mistakes: *(int *)NULL = 22; writing past end of allocated buffer, accessing previously freed memory, junk pointers
And now, for a large example!
image.c
Remember PiC.c and PiC.h from the homework?
#include "PiC.h" #include <string.h> int main(int argc, char *argv[]) { int i; char *my_name; my_name = argv[0]; for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) { printf( /* * includes "usage:\n" */ " %s [ options ]\n" "options:\n" #include <stdlib.h> " -h || --help this help message\n" #include <stdio.h> my_name); exit(0); } else fprintf(stderr, "%s: unknown option ’%s’; use -h for help\n", my_name, argv[i]); } return(0); }
First thing we need, is to pull in the header #include "PiC.h" file
Recommend
More recommend