Вы находитесь на странице: 1из 28

Computing 2 2015x1 Summer Session

Linked Lists and Function


Pointers
Lecturer

Angela Finlayson

COMPILING
For compiling for normal use
gcc Wall Werror O o prog prog.c

For compiling to run gdb


gcc Wall Werror gdwarf-2 o prog prog.c

For compiling to run valgrind


gcc Wall Werror g o prog prog.c

Compiling with more than 1 c file, normal use


gcc Wall Werror O o prog prog.c f2.c f3.c f4.c

WHAT IS A LINKED LIST?

Linked lists:

sequential collection of items (i.e. no random access)


we can only get to the second by accessing the first, and so on
we cant access the nth element of a list directly

easy to re-arrange

deleting or inserting is simple

self-referent structure (may be cyclic)

a list element contains a link to another list element

WHAT IS A LINKED LIST?

A linked list is a set of items where each item is part of a


node that also contains a link to a node. (We also call the list
items list elements)

The final element:


1.contains a null link, pointing to no node, or
2.refers to a dummy node (also called sentinel) containing no item
3. may be the first node (hence the list is circular)

WHAT IS A LINKED LIST?


A possible C implementation: (Please see tutorial 1
for another implementation)
insert definition for

Item

typedef

int

Item;

typedef struct node * link;


struct node {
Item item;
link next;
};

item

next

Sedgewick

item

next

here

COMMON OPERATIONS ON LISTS


Memory allocation
link x = malloc (sizeof *x);
// RIGHT
link y = malloc(sizeof(struct node)); //RIGHT
link z

= malloc(sizeof(link));

//WRONG

Traversing a list

for (curr = start; curr != NULL; curr = curr->next) {


<< do something with the node >>
}

OPERATIONS ON LISTS

Remove the first item in the list


this interface doesnt work!
//Remove the first node from the list and free mem.
void deleteFirstItem (link ls);

either return new list as result: or pass a pointer to the link

SOME OPERATIONS ON LISTS

Delete the first item from a list:


list

item

next

item

next

item

next

item

list = deleteFirstItem(list);
list

item

next

item

next

item

next

next

OPERATIONS ON LISTS

Delete function
Delete after element curr:

//delete node after curr from list and free memory


void deleteNext (link curr);

curr

curr

item

next

item

next

item

next

PROBLEM: DELETION

Deletion is awkward, as we always have to keep track of the


previous node:
prev->next = curr->next;
free (curr);

Can we delete a node if we only have the pointer to the


node itself?

We may need to traverse the whole list (if we have a reference to


the head) to find the predecessor of curr!

Idea: every node stores a link to the previous node, in addition to


the link to the next node

A SINGLY LINKED LIST EXAMPLE

Implement a function which given a linked list, reverses the


order of items
link reverse (link list) {

SINGLY LINKED LIST EXAMPLE

Implement a function which given a linked list, reverses the


order of items
link reverse (link list) {

link tmp;
link curr = list;
link rev = NULL;
while (curr != NULL) {
tmp = curr->next;
curr->next = rev;
rev = curr;
curr = tmp;
}
return rev;
}

ANOTHER SINGLY LINKED LIST EXAMPLE

Implement a function which given a linked list, finds the node


with the smallest item in the list and moves it to the front of the
list. Other nodes remain unchanged.
/Assume our items can be compared using
// <, >, <= or >= etc.
// If there are duplicate smallest items
just move the
// first occurrence.
link smallestFirst (link list) {

homework!!!!

DOUBLY LINKED LISTS


Move forward and backward in such a list
Delete node in a constant number of steps

prev

item

next

prev

item

next

typedef struct dnode * dlink;


typedef struct dnode {
Item item;
dlink next;
dlink prev;
} ;

prev

item

next

DOUBLY LINKED LISTS

Deleting nodes

easier, more efficient

Other basic list operations

pointer to previous node is necessary in many


operations, doesnt have to be maintained separately for
doubly linked lists
twice the number of pointer manipulations necessary for
most list operations
memory overhead to store additional pointer

#include <stdlib.h>
#include <stdio.h>
#include "lists.h"

void deleteNext(link curr){


if(curr != NULL){
link delNode = curr->next;
if(delNode != NULL){
curr->next = delNode->next;
free(delNode);
}
}
}
link deleteFirstItem(link list){
if(list != NULL){
link delNode = list;
list = list->next;
free(delNode);
}
return list;
}
void printList(link list){
link curr;
for(curr = list; curr != NULL; curr= curr->next){
printf("%d ",curr->item);
}
printf("\n");
}
link newList(){
return NULL;
}
link newNode(Item item){
link n = (link) malloc(sizeof(*n));
n->item = item;
n->next = NULL;
return n;
}
//O(n)
link insertEnd(link list, link n){
link curr;
if(list == NULL){
list = n;
} else {
for(curr = list; curr->next != NULL; curr = curr->next){
}
curr->next = n;
}
return list;
}
//O(1)
link insertFront(link list, link n){
n->next = list;
return n;
}

Traversing the list (insert at front or end)


it is cheaper to insert a node at the front than the end,
because you dont have to traverse the entire list if
you insert a node at the front of the list (see
insertEnd, insertFront)
o if you have to traverse nothing (insertFront), we
say it is of an order 1 since the number of
elements in the list does not affect the number of
things you have to check (i.e. O(1))
o if you traverse a million things since there are a
million members, it is of order n (i.e. O(n))

FUNCTION POINTERS
C can pass functions by passing a pointer to them.
E.g. a pointer to a function mapping int int

int (*fun)(int)

Function pointers ...

are references to memory addresses of functions


are pointer values and can be assigned/passed

Function pointer variables/parameters are declared as:

typeOfReturnValue (*fname)(typeOfArguments)

EXAMPLE OF FUNCTION POINTERS


int square(int x){ return x*x;}
int timesTwo(int x){return x*2;}

variable called fp here, and its a function pointer, which is only allowed to point to functions that have input/output that are ints

int (*fp)(int);
fp = &square;

//give fp the address of square

//fp points to the square function


(pass in value of 10 into function)

int n = (*fp)(10); //call the square function with input 10


fp = timesTwo;

//works without the &


//fp points to the timesTwo function

ways of calling the function

n = (*fp)(2);

//call the timesTwo function with input 2

n = fp(2);

//can also use normal function call


//notation

mystery.c
#include <stdio.h>

inputs for mystery: int int and function pointer

int mystery(int a, int b, int (*fn)(int,int)) {


return ((*fn)(a,b));
takes function fn, and runs in
}

by passing in a and b

int gcd(int a, int b) {


first, executes sum(a,b)
int c;
while ( a != 0 ) {
then gcf(a,b)
c = a;
then sumofsquares(a,b)
a = b%a;
b = c;
}
return b;
}
point to a function
int sumofsquares(int x, int y) {
by using a variable
return (x*x + y*y);
}
and then call the
int sum(int x, int y) {
function through the
return (x + y);
}
variable
int main(){
int n = mystery(8,12,sum);
printf("%d \n", n);
printf("%d \n", mystery(8,12,gcd));
printf("%d \n", mystery(8,12,sumofsquares));
return 0;
}

example1.c

#include <stdio.h>
void printSomething(int x){
printf("%d\n",x);
}
int square(int x){
return x*x;
}
int absVal(int x){
if(x < 0) return -x;
return x;
}

variable fp is a
function pointer which
only allows us to point
to functions which have
one int as an input and
one int as an output

int main(int argc, char * argv[]){


int (*fp)(int);
fp = square;
//make variable point to square function

int n = (*fp)(10); //call the function fp, which is square, and


pass in 10

printf("The answer is %d\n",n);


fp = absVal;

//fp points to absVal function

//pass in -99 into absVal


n = fp(-99);
printf("The answer is %d\n",n);

fp = printSomething;
return 0;
}

//fp can't point to printSomething


function because it doesn't have an int
out (it is a void function) so the program
won't compile

FUNCTION POINTERS

Higher-order functions: functions that get other


functions as arguments, or return functions as a result
Example: the function traverse takes a list and a
function pointer as argument, and applies to function to
all nodes in the list

void printList(link ls){


link curr = ls;
//set curr to beginning of list
while(curr != NULL){
printf(%d ,curr->data); //Process the node
curr = curr->next;
//move to next node
}
}

//print the data in the node

function f only runs on a pointer to one of the nodes


& the function must fit this prototype

// apply function f to all nodes in ls


//general traversal function, it doesn't know what we're
void traverse (link ls, void (*f) (link)){
link curr = ls;
while(curr != NULL){
//it runs the function f, but it doesnt know what the function does
(*f) (curr);
curr = curr->next; // passes in curr, then moves to next node
}
}

gonna do with the function

USING FUNCTION POINTERS


void printNode(link ls){
if(ls != NULL){
printf("%d->",ls->data);
}
}

//posibillities for functions that traverse can call

//print the data

//function must have the correct prototype

//process the data, and if its larger or equal


void printGrade(link ls){
if(ls != NULL){
if(ls->data>= 85){
printf("HD ");
} else {
printf("FL ");
}
}
}
// apply function f to all nodes in ls
void traverse (link ls, void (*f) (link)){ //f must have prototype void f(link)
link curr = ls;
while(curr != NULL){
(*f) (curr);
curr = curr->next;
}
}

to 85, it prints HD, else prints FL

//To call the function


traverse(myList,printNode); //function passed in must have the right prototype
traverse(myList,printGrade);

lists.h

typedef int Item;


typedef struct node * link;
struct node{
Item item;
link next;
};
void multByTwo(link ls);
void divideByTwo(link ls);
void
link
link
link
link
link
void

printList(link list);
newList();
newNode(Item item);
insertEnd(link list, link n);
insertFront(link list, link n);
deleteFirstItem(link list);
deleteNext(link curr);

// These functions were created to demonstrate the


// use of function pointers
void traverse(link ls, void (*visit) (link));
void traverseIf(link ls, void (*visit) (link),int (*f)
(Item));
//int (*f) (Item)
int isNegative(Item item);
int isOdd(Item item);
int isFail(Item item);
//void (*visit) (link)
void printGrade(link ls);
void printNode(link ls);
void printValue(link ls);

WHAT DOES THIS CODE DO


see useList.c

CONTINUED
main .c file of prev page
useList.c

#include <stdio.h>
#include <stdlib.h>
#include "lists.h"
int main(int argc, const char * argv[]){
int i;
link myList = newList();
for(i=-9; i < 100; i = i+9){
myList = insertEnd(myList,newNode(i));
}
printList(myList);
traverse(myList,printGrade);
traverse(myList,printNode);
traverse(myList,multByTwo);
traverse(myList,printValue);
traverse(myList,divideByTwo);
traverse(myList,printValue);
printf("Negative ");
traverseIf(myList,printNode,isNegative);
traverseIf(myList,printGrade,isOdd);
traverseIf(myList,printNode,isOdd);
traverseIf(myList,printNode,isFail);
return 0;
}

//print the node only


if it fails

CONTINUED
lists.c
file with all the function implementation (page 1 of 2)
#include <stdlib.h>
#include <stdio.h>
#include "lists.h"
void printList(link list){
link curr;
for(curr = list; curr != NULL; curr= curr->next){
printf("%d ",curr->item);
}
printf("\n");
}
link newList(){
return NULL;
}
link newNode(Item item){
link n = (link) malloc(sizeof(*n));
n->item = item;
n->next = NULL;
return n;
}
//O(n)
link insertEnd(link list, link n){
link curr;
if(list == NULL){
list = n;
} else {
for(curr = list; curr->next != NULL; curr = curr->next){
}
curr->next = n;
}
return list;
}
//O(1)
link insertFront(link list, link n){
n->next = list;
return n;
}
// These functions were created to demonstrate the use of function pointers
void printValue(link ls){
if(ls != NULL){
printf("%d ",ls->item);
}
}
void printNode(link ls){
if(ls != NULL){
printf("%d->",ls->item);
}
}

CONTINUED
lists.c
page 2 of 2
void printGrade(link ls){
if(ls != NULL){
if(ls->item >= 85){
printf("HD ");
} else if (ls->item >= 50){
printf("PS ");
}else {
printf("FL ");
}
}
}
void multByTwo(link ls){
if(ls != NULL){
ls->item = ls->item * 2;
}
}
void divideByTwo(link ls){
if(ls != NULL){
ls->item = ls->item / 2;
}
}
int isOdd(Item item){
return (item%2 != 0);
}
int isNegative(Item item){
return (item < 0);
}
int isFail(Item item){
return (item < 50);
}
void traverse(link ls, void (*visit) (link)){
link curr;
for(curr = ls; curr!= NULL; curr = curr->next){
visit(curr);
}
printf("\n");
}

TRAVERSEIF
void traverseIf(link ls, void (*visit) (link),int (*f) (Item)){
link curr;
for(curr = ls; curr!= NULL; curr = curr->next){
//Do we want to visit this node ?
if(f(curr->item)){
//function pointer here determines
visit(curr);
we want to visit the node or not
}
}
//function pointer to actually
printf("\n");
visit the node
}

if

//OR (*visit)(curr) but either works

Вам также может понравиться