Lecture 6: Structures, Pointers, Linked Lists Reminder: Pointers and structures Pointers to structures Dynamic memory allocation: malloc Linked lists Ordered linked lists Double linked lists, Trees
Reminder: Pointers Pointers are address-variables. They contain information about where another variable can be found in the memory (the variable they point at). Pointers are useful when working with arrays and as function arguments. 0x5000 array[0] int i, array[5]; int *arr_ptr; arr_ptr = array; for (i=0; i<5; ++i) printf\( %d, *\(arr_ptr+i)); int number; scanf\( %d,&number\); (array_ptr+3) 0x5003 0x5001 0x5002 0x5003 0x5004 array[1] array[2] array[3] array[4] Address of operator (&) pointer dereference (*)
Reminder: Structures struct can be used to define new structures struct emp_record { char name[30]; integer emp_id; integer age; ; struct emp_record emp1, emp2; emp1.age = 31; emp2.name = John Smith ; struc can be used as return value and arguments in functions You can also define arrays of struct struct emp_record postgrad[100];... postgrad[17].name = John Smith ;
Pointers to structures You can also define pointers to structures struct emp_record *emprec_ptr; (*emprec_ptr\).name = John Smith ; more efficient for function calls ( is not copied)
Pointers to structures You can also define pointers to structures struct emp_record *emprec_ptr; (*emprec_ptr\).name = John Smith ; more efficient for function calls ( is not copied) (*emprec_ptr).name can also be written as emprec_ptr->name struct emp_record *emprec_ptr; emprec_ptr->name = John Smith ;
Pointers to structures You can also define pointers to structures struct emp_record *emprec_ptr; (*emprec_ptr\).name = John Smith ; more efficient for function calls ( is not copied) (*emprec_ptr).name can also be written as emprec_ptr->name struct emp_record *emprec_ptr; emprec_ptr->name = John Smith ; A struct can also contain fields that are pointers (even pointers to another struct of the same kind) struct _node { char [100]; struct _node *next_node; linked list
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program static: int a[100]; allocates 100x4 bytes in stack and calls it a
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program static: int a[100]; allocates 100x4 bytes in stack and calls it a dynamic: #include<stdlib.h> #include<stdio.h> int dim; int *a_ptr; scanf\( %d,&dim\); a_ptr = malloc(sizeof(int)*dim);... free(a_ptr); a_ptr = NULL;
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program static: int a[100]; allocates 100x4 bytes in stack and calls it a dynamic: malloc allocates the #include<stdlib.h> specified number of bytes in #include<stdio.h> heap memory and returns a int dim; generic pointer to it. int *a_ptr; scanf\( %d,&dim\); a_ptr = malloc(sizeof(int)*dim);... free(a_ptr); a_ptr = NULL;
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program static: int a[100]; allocates 100x4 bytes in stack and calls it a dynamic: #include<stdlib.h> #include<stdio.h> int dim; int *a_ptr; scanf\( %d,&dim\); a_ptr = malloc(sizeof(int)*dim);... malloc allocates the specified number of bytes in heap memory and returns a generic pointer to it. free deallocates the memory assigned to a_ptr free(a_ptr); a_ptr = NULL;
malloc dynamic memory allocation Data is stored in two different areas of memory: stack and heap static; allocated at time of function call; deallocated when function is terminated dynamic; allocated on demand; persists for duration of the program static: int a[100]; allocates 100x4 bytes in stack and calls it a dynamic: #include<stdlib.h> #include<stdio.h> int dim; int *a_ptr; scanf\( %d,&dim\); a_ptr = malloc(sizeof(int)*dim);... malloc allocates the specified number of bytes in heap memory and returns a generic pointer to it. free deallocates the memory assigned to a_ptr free(a_ptr); a_ptr = NULL; Heap memory can only be accesses via pointers (no named variables)!
malloc: example #include<stdio.h> #include<stdlib.h> main() { int dim, i; int *a_ptr; srand(time(null)); /* initializes random number generator */ printf("specify array dimension: "); scanf("%d", &dim); /* now use malloc to allocate the correct amount of memory */ a_ptr = (int*) malloc(sizeof(int)*dim); /* Assign pseudo-random numbers to the elements of the array */ for (i=0; i < dim; ++i) a_ptr[i] = rand() % 100 + 1; /* Now print out the array */ for (i=0; i < dim; ++i) printf("a_ptr[%d] = %d\n", i, *(a_ptr+i)); return(0);
#include<stdio.h> #include<stdlib.h> main() { int dim, i; int *a_ptr; malloc: example http://www.tcd.ie/physics/people/claude.ederer/teaching/3c01/use_malloc.c srand(time(null)); /* initializes random number generator */ printf("specify array dimension: "); scanf("%d", &dim); /* now use malloc to allocate the correct amount of memory */ a_ptr = (int*) malloc(sizeof(int)*dim); /* Assign pseudo-random numbers to the elements of the array */ for (i=0; i < dim; ++i) a_ptr[i] = rand() % 100 + 1; /* Now print out the array */ for (i=0; i < dim; ++i) printf("a_ptr[%d] = %d\n", i, *(a_ptr+i)); return(0); Exercise: Modify program so that it also calculates the a verage o ver all values of a_ptr.
Linked lists Idea: Each element of the list contains a pointer to the next element first_ptr 3 17 99 NULL
Linked lists Idea: Each element of the list contains a pointer to the next element first_ptr 3 17 99 NULL Adding a new element at the beginning of the list: struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(struct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr;
Linked lists Idea: Each element of the list contains a pointer to the next element first_ptr 3 17 99 NULL Adding a new element at the beginning of the list: struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(stru ct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr;
Linked lists Idea: Each element of the list contains a pointer to the next element first_ptr 3 17 99 NULL 8 Adding a new element at the beginning of the list: struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(stru ct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr;
Linked lists Idea: Each element of the list contains a pointer to the next element first_ptr 3 17 99 NULL 8 Adding a new element at the beginning of the list: struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(stru ct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr;
Linked lists Idea: Each element of the list contains a pointer to the next element NULL first_ptr 3 17 99 8 Adding a new element at the beginning of the list: struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(stru ct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr;
An example #include<stdlib.h> #include<stdio.h> struct linked_list { int ; struct linked_list *; ; struct linked_list *first_ptr = NULL; /* Function to add a list element */ void add_list(int number) { struct linked_list *new_item_ptr; new_item_ptr = malloc(sizeof(struct linked_list)); new_item_ptr-> = number; new_item_ptr-> = first_ptr; first_ptr = new_item_ptr; return; /* Function to print out list */ void print_list() { struct linked_list *current_ptr; current_ptr = first_ptr; while (current_ptr!= NULL){ printf("%d\n",current_ptr->); current_ptr = current_ptr->; return; main() { int value; while (1){ printf("enter number (0 to stop): "); scanf("%d", &value); if (value == 0) break; add_list(value); print_list(); return(0);
Example: Ordered list A function to create an ordered list of numbers (see: linked_list2.c) void enter_list(int number) { struct linked_list *before_ptr; struct linked_list *after_ptr; struct linked_list *new_item_ptr; before_ptr = first_ptr; if (before_ptr == NULL){ add_list(number); return; if (before_ptr-> >= number){ add_list(number); return; after_ptr = before_ptr->; while (1) { if (after_ptr == NULL) break; if (after_ptr-> >= number) break; after_ptr = after_ptr->; before_ptr = before_ptr->; new_item_ptr = malloc(sizeof(struct linked_list)); new_item_ptr-> = number; before_ptr-> = new_item_ptr; new_item_ptr-> = after_ptr; return;
Double-linked lists head_ptr NULL 19 8 32 NULL prev_ptr prev_ptr prev_ptr tail_ptr
Double-linked lists head_ptr NULL 19 8 32 NULL prev_ptr prev_ptr prev_ptr tail_ptr struct double_list { int ; struct double_list *; struct double_list *prev_ptr; ;
Double-linked lists head_ptr NULL 19 8 32 NULL prev_ptr struct double_list { int ; struct double_list *; struct double_list *prev_ptr; ; prev_ptr prev_ptr tail_ptr void add_head(int number){ struct double_list *new_item_ptr; new_item_ptr = malloc(sizeof(struct double_list)); new_item_ptr-> = number; new_item_ptr-> = head_ptr; head_ptr = new_item_ptr; */ /* now establish the backward links */ new_item_ptr->prev_ptr = NULL; if (new_item_ptr-> == NULL) /* First element tail_ptr = new_item_ptr; else new_item_ptr->->prev_ptr = new_item_ptr;
Double-linked lists head_ptr NULL 19 8 32 NULL prev_ptr struct double_list { int ; struct double_list *; struct double_list *prev_ptr; ; prev_ptr prev_ptr tail_ptr Try writing functions add_tail, print_fwd, print_bwd, enter (ordered double list)! void add_head(int number){ struct double_list *new_item_ptr; new_item_ptr = malloc(sizeof(struct double_list)); new_item_ptr-> = number; new_item_ptr-> = head_ptr; head_ptr = new_item_ptr; */ /* now establish the backward links */ new_item_ptr->prev_ptr = NULL; if (new_item_ptr-> == NULL) /* First element tail_ptr = new_item_ptr; else new_item_ptr->->prev_ptr = new_item_ptr;
Tree structures l_ptr r_ptr struct node { int ; struct node *l_ptr; struct node *r_ptr; ; l_ptr r_ptr l_ptr r_ptr Trees can be more efficient to search through Use recursion with trees But: important to create a well-balanced tree
Summary use malloc/free to dynamically allocate space in heap memory heap memory can only be accessed via pointers (no named variables) linked lists are dynamically growing/shrinking structures other structures: ordered lists, doubly linked lists, trees... entry pointer is needed (first_ptr, head_ptr, tail_ptr,...) take care not to lose links between list elements