<<

CS246 Lec16

Section 1 Today’s Goals The Dangling Reference Problem

• More on Pointers • An unassigned pointer (i.e. not pointing to  The any memory) is known as a dangling pointer.  Pointer arithmetic • Dereferencing any such pointers will surely result in a or error.  Pointers to pointers  Always assign your pointers to malloced  const and pointers memory or by & of a variable. • Function pointers  Remember that stack variables (i.e. locals in • Memory blocks functions) are deallocated as soon as a function returns. Therefore, avoid assigning pointers to addresses of such variables. CS246 1 Lec16 CS246 2 Lec16

Section 2 Pointer Arithmetic Pointers to Pointers • These operations are only well-defined if • A variable can be modified by a function if and the address involved are within a single only if it is passed by reference/pointer. memory block (array or malloced) • If the variable to be modified is a pointer itself,  The sum of a pointer and an integer one must pass a pointer to pointer, i.e. one must always add an extra level of referencing.  The difference of a pointer and an integer int make_node(Node **new) {  Pointer comparison *new=(Node *)malloc(sizeof(Node));  The difference between two pointers if (*new != NULL) return 1; else return 0; } CS246 3 Lec16 CS246 4 Lec16

Section 3 Section 4 Use const to Protect Pointers Function Pointers • We already know that keyword const • Function pointers point to memory addresses prevents the value of a variable from being where functions are stored. changed.  int (*fp) (void);  const int x;  A function pointer determines the prototype of a  void f(const int *p); function, but not its implementation.  Any function of the identical prototype can be  Prevents *p from being changed assign to the function pointer.  void f(int * const p);  A function without its argument lists becomes its  Prevents the pointer p itself from being changed own pointer  void f(const int * const p);  Function pointers do not need & or *

CS246 5 Lec16 CS246 6 Lec16

1 CS246 Lec16

Function Pointer: Example Overriding Functions

• Also known as late-binding, this is emulated in with #include function pointers. • Together with generic pointers (void *), one can have int main() { typeless parameters and functions. int i = 1; void fd (void *base, size_t n, size_t size){ int (*fp) (const char *, ...) = printf; double *p = base; fp("i == %d\n", i); for (p = base; p < (double*) (base+(n*size)); p++) ; (*fp)("i == %d\n", i); } return 0; int main() { double a[5] = {0, 1, 2, 3, 4}; } if (type == DOUBLE) { • Notice no need for or void (*f) (void *, size_t, size_t) = fd; &printf (*fp) (*f)(a, 5, sizeof(double)); • But I like to stick with (*fp) } } CS246 7 Lec16 CS246 8 Lec16

Printing of Generic Arrays Printing of Generic Arrays typedef struct { void gp (void *b, size_t n, size_t size){ double x; char *p; for (p=b; p <(char*)(b+(n*size)); p+=size){ double y; switch (size) { } Point; case sizeof(double): int main() { printf("%.2f ", *(double*)p); break; double a[5] = {0, 1, 2, 3, 4}; case sizeof(int): int b[5] = {5, 6, 7, 8, 9}; printf("%d ", *(int*)p); break; Point ps[2] = {{0.5, 0.5}, {1.5, 2.5}}; case sizeof(Point): printf("x = %.2f ", ((Point *)p)->x); gp(a, 5, sizeof(double)); printf("y = %.2f ", ((Point *)p)->y); gp(b, 5, sizeof(int)); break; }} gp(ps, 2, sizeof(Point)); printf("\n"); } } CS246 9 Lec16 CS246 10 Lec16

qsort qsort Example

• qsort and its comparison function: int vs[] = {40, 10, 100, 90, 20, 25};  sorts a generic array of any type int comp ( const void *a,  stdlib.h const void *b){  void qsort(void *base, size_t ne, size_t s, return ( *(int*)a - *(int*)b ); int (*compar) (const void *, const void *)); }  base points to the start (array) element  ne is the number of elements to be sorted int main () {  s is the size of the elements (in the array) qsort (vs, 6, sizeof(int), comp);  compar is the generic comparison function } supplied by user

CS246 11 Lec16 CS246 12 Lec16

2 CS246 Lec16

compar Simulating Methods int comp_nodes (const void *a, const void *b) { struct Node *n1 = a; struct Node *n2 = b; • Function pointers used together with struct  typedef struct _Node { if ( (n1->num < n2->num ) return -1; int num; else if (n1->num > n2->num ) return 1; else return 0; struct Node *prev; /* or struct Node *next; return ((struct Node *)n1)->num - ((struct Node *)n2)->num; */ struct Node * (*make_node) (int); } } Node;

qsort(nodes, 10, sizeof(struct Node), comp_nodes);

CS246 13 Lec16 CS246 14 Lec16

Other Uses of Function Pointers Other Uses of Function Pointers

• Function pointers can be used like any • Function returning pointer to function pointers. • Function that takes a double and returns a  Array of function pointers pointer to a function which takes a char * void (*file_cmd[])(void) = { new_cmd, and returns an int: open_cmd, close_cmd,  Without typedef: save_cmd, print_cmd, int (*f(double)) (char *); exit_cmd  With typedef: }; typedef int (*Pfunc) (char *); Pfunc f(double);

CS246 15 Lec16 CS246 16 Lec16

Section 5 Section 6 File I/O on Memory Working with Memory Blocks Blocks:Binary Files • Generic pointers can not be dereferenced. • Binary files do not have a line-oriented • string.h functions to work with typeless structure. memory blocks pointed to by void *.  void *memcpy(void *des,void *src,size_t l); • They consist of blocks of objects, and the  void *memmove(void *des,const void *src,size_t l); format of these objects are application as  int memcmp(const void *p,cost void *q,size_t l); well as machine dependent.  void *memchr(const void *p, int val, size_t l); • These are generic versions of the corresponding string • When opening a binary file, always append functions (strcpy, strcmp and strchr). a 'b' to the second argument, i.e. • memmove is used instead of memcpy if the two blocks  fopen("test.exe", "wb"); overlap.  fopen("test.exe", "rb"); CS246 17 Lec16 CS246 18 Lec16

3 CS246 Lec16

Current File Position Read/Write a Binary File

• long ftell(FILE *fp); • size_t fread(void *buf, size_t s, size_t ne, FILE *in); • Returns the current file position, or . –1L • Reads up to ne elements, each of size s in • fseek is used to set the file position: and stores them in buf fseek(fp, -sizeof(double), SEEK_CUR); • size_t fwrite(const void *buf, size_t s, sizt_t ne, FILE *out); • ftell’s return value is often used by fseek: • Similarly, writes from buf up to ne blocks, long pos; each of size s pos = ftell(fp); • Number of elements (not bytes!) successfully /* some code */ read/written is returned fseek(fp, pos, SEEK_SET); CS246 19 Lec16 CS246 20 Lec16

Examples Summary • Converting a text file of ints to binary: while (fscanf(in, "%d", &i) == 1) • Be careful with pointers! if (fwrite(&i,sizeof(int),1,out)!=1){ fprintf(stderr, "Error writing file\n"); • Function pointers can be really useful, break;} especially when writing larger applications. • fwrite is convenient for storing data in a file temporarily (or another program), which can later • fread and fwrite are designed to copy be read back with fread. large chunks of memory from/to file. long pos; pos = ftell(fp); fpos_t pos; fgetpos(fp, &pos); • Although primarily used in binary file I/O, fwrite(&n, sizeof(struct Node), 1, fp); with a little care in address/size calculation, fseek(fp, pos, SEEK_SET); fsetpos(fp, &pos); they can be used with text files just as well. fread(&n,sizeof(n), 1, fp); CS246 21 Lec16 CS246 22 Lec16

4