Title: C struct, pointer, and linked list
1C struct, pointer, and linked list
2Overview
- Structure
- Nested structure, pointer to structure, structure
as parameter - Pointer
- Dynamic variables, malloc, free, NULL
- Linked list
- Add / Delete a node, traverse a linked list
- Modules
3Structure
struct Date int day, month, year void
main ( ) Date birthday 18, 2, 1999
Date today today.day 28 today.month
2 today.year 2002
today
28
today.day
2
today.month
2002
today.year
birthday
18
birthday.day
2
birthday.month
1999
birthday.year
4Structure
- Group related fields into a structure
struct date int day, month, year
typedef struct date int day, month, year
Date
struct date today
typedef struct int day, month, year Date
struct date today or Date today
Date today
5Accessing Fields in Structure
Date today today.day 28 today.month
2 today.year 2002 printf("This year
is d", today.year)
To access a field, we use the dot operator. e.g.
today.year is the year field of the structure
today.
6Nested Struct, Array of Struct
struct Date int d, m, y struct Student
char name60 double averageScore Date dob
/ date of birth / struct Class Student
stud30 int numStud
7Nested Record, Array of Record
... int main ( ) Class mccs170 Date
someday mccs170.numStud 12
strcpy(mccs170.stud0.name, "Peter")
mccs170.stud0.averageScore 88 someday.d
1 someday.m 1 someday.y 1980
mccs170.stud0.dob someday
We can copy structure using
8Exercise
Q1) Write statements to initialize the record of
student no. 1 as follows. Name Tommy Average
score 91 Date of birth 2 Apr 1980 int main ( )
Class mccs170
9Pointer to Structure
struct Date int d, m, y int main ()
Date today 8, 3, 2002 Date p p
today ...
today
8
today.d
Notice p.d means (p.d), not (p).d.
3
today.m
2002
today.y
10Structure as Input Parameter
struct Date int d, m, y void print_date
(Date aday) printf("d/d/d", aday.d,
aday.m, aday.y) int main () Date today
8, 3, 2002 print_date(today) ...
Passing structure as parameter is similar to
passing integer variables. aday and today
are two separate variables.
11Exercise
Q2) Write the following function. struct Date
int d, m, y void print_date2 (Date aday)
char months124 "Jan", "Feb", "Mar",
"Nov", "Dec" / print the date in the
format 25 Dec 2000 /
12Exercise
Q3) Write the following function which returns
the day of week of the day. struct Date int
d, m, y int dayofweek (Date aday)
13Exercise
Q3 cont) You can use the following algorithm to
compute the day of week. w (d(13m-1)/5 2c
y y/4 c/4) 7 if (wlt0) w7 whered is
the day (1-31)m is month (1Mar, , 10Dec,
11Jan, 12Feb) Treat Jan and Feb as month of
the preceding year y is year (2000 has y 00
except y 99 for Jan and Feb), c is century
(1999 has c 19. 2000 has c 20 except c 19
for Jan and Feb), w is week day (0 Sunday, ...,
6 Saturday).
14Structure as Output Parameter
void scan_date (Date aday) int dd, mm, yy
scanf("d d d", dd, mm, yy) (aday).d
dd (aday).m mm (aday).y yy int
main () Date today scan_date(today)
print_date(today) ...
We need to pass pointer to structure to a
function that modifies the structure, similar to
integer.
15Pointer to Structure
void scan_date (Date aday) int dd, mm, yy
scanf("d d d", dd, mm, yy) aday-gtd
dd aday-gtm mm aday-gty yy
A shorthand (aday).d same as aday-gtd (aday).m
same as aday-gtm
16Pointer to Structure
void scan_date (Date aday) scanf("d d d",
aday-gtd, aday-gtm, aday-gty)
If we want to set the fields of a structure by
scanf, we need to pass the address of the fields.
17Structure as Parameter
void print_date (Date aday)
printf("d/d/d", aday.d, aday.m, aday.y)
void scan_date (Date aday) scanf("d d
d", aday-gtd, aday-gtm, aday-gty)
18Comparing content of structure
struct Date int d, m, y int main ( )
Date day1 11, 2, 1999 Date day2 1,
12, 1999 ... if (day1day2)
?
Although we can use "" to copy structure, we
cannot compare structure by "".
19Exercise
struct Date int d, m, y struct Student
char name60 double averageScore Date dob
/ date of birth / struct Class
Student stud30 int numStud
The following exercises assume the definition
here.
20Exercise
int sameDay (Date day1, Date day2) ... int
main ( ) Date day1, day2 ... if
(sameday(day1,day2)) printf("It is the same
day\n")
Q4) Write a function to determine whether two
Date is the same.
21Exercise
Q5) Write a function to check whether student
1 is younger than student 2. int isYounger
(Student stud1, Student stud2) ..
22Static Variable
int isPrime (int x) for (int k2 kltx/2
k) if (xk0) return 0 return 1 int
sumPrime (int N) int sum 0 for (int i1
iltN i) if (isPrime(i)) sumi return
sum int main ( ) int ans sumPrime(10)
Storage area for local and global variables are
allocated and freed automatically. They are
sometimes called static variables. Local
variables are created in calling a function and
destroyed when the function returns.
23Static Variable
int isPrime (int x) for (int k2 kltx/2
k) if (xk0) return 0 return 1 int
sumPrime (int N) int sum 0 for (int i1
iltN i) if (isPrime(i)) sumi return
sum int main ( ) int ans sumPrime(10)
Local variables of main
ans
24Weakness of Static Variable
// refer to slide 6 for detail struct Class
Student stud30 int numStud
The storage space is controlled by the C
compiler. We must hardcode the number and size
of variables in the program. In the previous
example, we fix the capacity (30) of a class, and
use numStud to store the actual number of
students. If there are less students, we waste
some spaces. If there are more than 30 students,
we will not be able to store them all.
25Pointer and Static Variable
include ltstdio.hgt void foo () int p, q
int a1 q a p q q 3 p 5
printf("d d d", a, p, q) int main ( )
foo()
q
a
p
1
p
q
A pointer to a static variable just gives an
alias to the variable. It does not affect the
allocation and de-allocation of the storage space.
26Pointer and Dynamic Variable
The true power of pointer is in the usage of
dynamic variables and different data structures.
27Need of Dynamic Variable
void student_register ( ) // allocate space
for the new student void student_graduate
(char name ) // free the space for the
graduated student
Sometimes, we dont know how much storage space
is needed when writing the program. We may want
to allocate space in a function and free the
space in another function. We need a more
flexible way to manage storage space.
28Dynamic Variables
- Dynamic variables are created and destroyed
manually. We call - malloc() to allocate, and
- free() to free
- storage space of a dynamic variable. Dynamic
variable can only be accessed through pointer.
29malloc( )
We use pointer and the function malloc() to
create dynamic variables. malloc() allocates
storage space.
int p double q Date r p (int)
malloc(sizeof(int)) q (double)
malloc(sizeof(double)) r (Date)
malloc(sizeof(Date))
p
r
q
30malloc( ), closer look
sizeof(int) the number of bytes occupied by an
int
int p p (int) malloc(sizeof(int))
malloc(2) allocates a storage cell of size 2.
i.e. allocates a cell big enough for an integer
p (int) malloc() Because p is a pointer to
int, we have to cast the RHS by (int). You can
think it as a hint to the C compiler that the
allocated cell will be pointed by a pointer to
integer.
31malloc( )
include ltstdlib.hgt int main () int p int
a2 p (int) malloc(sizeof(int)) p 4
p a free(p) p NULL
p
?
p
p
?
?
Allocate a cell big enough for an int, and make p
points to it.
We create a dynamic variable using pointer and
malloc(). Notice that the only name of the
dynamic variable is p. Therefore, we must
access the variable through pointer.
32free( )
include ltstdlib.hgt int main () int p int
a2 p (int) malloc(sizeof(int)) p 4
p a free(p) p NULL
p
?
p
p
p
?
?
Free the cell pointed by p
?
When a dynamic variable is no longer used, we
should free it. The compiler will not de-allocate
the storage space automatically.
33NULL
include ltstdlib.hgt int main () int p int
a2 p (int) malloc(sizeof(int)) p 4
p a free(p) p NULL
p
?
p
p
p
?
p
?
?
After free(p), p points to some rubbish. To
indicate that p now points to nothing, it is a
good practice to set p NULL. NULL is a special
pointer value.
34include ltstdlib.hgt
include ltstdlib.hgt int main () int p int
a2 p (int) malloc(sizeof(int)) p 4
p a free(p) p NULL
The function malloc(), free() and the special
value NULL are defined in the header file
stdlib.h. You should include it when you use
dynamic variables.
35q p
int p, q p (int)malloc(sizeof(int)) q
(int)malloc(sizeof(int)) p 3 q p
p
3
p
q
q
36q p
p
3
p
int p, q p (int) malloc(sizeof(int)) q
(int) malloc(sizeof(int)) p 3 q p
q
q
37Example
include ltstdlib.hgt int main () int p, q
int r p (int) malloc(sizeof(int)) r
p q (int) malloc(sizeof(int)) p 3
q p r (A) free(r) (B) r NULL
(C)
Remember, free(r) means free the dynamic
variable pointed by the pointer r. It does not
change r. And after free( ), r and p will be
rubbish.
38Exercise
include ltstdlib.hgt int main () int p, q
int r int s p (int)
malloc(sizeof(int)) r p p 5 p
(int) malloc(sizeof(int)) q p s r q
s 1 r p 2 (A) free(r) r
NULL free(q) q NULL (B)
Q6) Use a diagram to illustrate the state of
dynamic variables at the point A and B.
39Memory Leak
include ltstdlib.hgt int main () int p, q
p (int) malloc(sizeof(int)) p 12 (A)
p (int) malloc(sizeof(int)) scanf("d",
p) (B) free(p) p NULL (C)
p
p
3
(A)
p
3
(B)
q p or free(p)
p
8
p
3
(C)
A dynamic variable must be accessed through a
pointer. So before you change a pointer, (e.g. p
q p(int)malloc() pNULL), beware that p
might not be accessible any longer.
40Invalid Pointer De-reference
include ltstdlib.hgt int main () int p, q
p (int) malloc(sizeof(int)) q p q
3 (A) free(q) q NULL (B)
printf("d d", p, q) p 999 q 999
?
After free(q), the cell p (and q) disappears.
Therefore, we can no longer use p or q.
41Free unused cell once, and only once!
include ltstdlib.hgt int main () int p, q
p (int) malloc(sizeof(int)) q p q
3 (A) free(q) q NULL (B) p NULL
(C)
Free each unused cell once, and only once. (NOT
free each pointer once)
42Dont Free Static Variable
include ltstdlib.hgt int main () int p, q
int a 5 p (int) malloc(sizeof(int)) q
a p 3 (A) free(p) p NULL (B)
q NULL (C)
a
You only need to free dynamic variable. Never
free static variable. Remember, free( ) what you
malloc( ).
43Dynamic Array
include ltstdlib.hgt int main () int p int
size5 p (int) malloc(sizeof(int)size)
for (int i0 iltsize i) pi i (A)
free(p) p NULL (B)
p
p0
0
(A)
1
2
3
4
p4
p
(B)
You can also create an array as dynamic variable
using malloc( ). The array size need not be
fixed at compile time.
44Linked List, Introduction
As we create more and more student records as
dynamic variable, we need some way to organize
our data. There are a lot of data structures.
Thats why there are two courses of Data
Structure!
45Linked List, Introduction
tom
p1
macao
10
mary
taipa
14
john
macao
22
ann
macao
18
One way to do this is to linked all the student
records together as a list with pointers.
46Linked List
head
b
head
c
Each node consists of two parts the data and the
next pointer. The pointer head points to the
first node of the linked list, the pointer
head-gtnext points to the second node, etc.
struct Node char data Node next Node
head
47Linked List
head-gtdata
head-gtnext-gtdata
b
head
c
head-gtnext-gtnext
struct Node char data Node next Node
head
head-gtnext
48Linked List
phead-gtnext
p-gtnext
p
b
head
c
p-gtdata
The next pointer of the last node NULL
The first node is pointed by a pointer called head
49Empty linked list
head
Empty linked list is represented by a head
pointer equal to NULL. Remember, head points to
the first node in a linked list. If the list is
empty, the first node does not exist.
For brevity, we usually dont draw the cell for
pointer.
head
50Example
include ltstdlib.hgt struct Node char data
Node next int main ( ) Node head
Node p p (Node) malloc(sizeof(Node))
p-gtdata 'a' (A) head p (B) p (Node)
malloc(sizeof(Node)) p-gtdata 'b' (C)
51Example
(C) head-gtnext p (D) p (Node)
malloc(sizeof(Node)) p-gtdata 'c' (E)
head-gtnext-gtnext p p-gtnext NULL (F)
52Exercise
Q7) The following program builds a linked list
containing the characters a, b, and c.
Trace the program carefully. Draw a diagram to
illustrate the values of the dynamic variables
and the pointers at the points (A), (B) and (C).
include ltstdlib.hgt struct Node char data
Node next
53Exercise
int main ( ) Node head NULL Node p
p (Node) malloc(sizeof(Node)) p -gtdata
'a' (A) p-gtnext (Node) malloc(sizeof(Node))
p-gtnext-gtdata 'b' p-gtnext-gtnext NULL
(B) head (Node) malloc(sizeof(Node))
head-gtdata 'c' head-gtnext p (C)
54Basic Operations
struct Node char data Node
next struct List Node head void
insert_list(List L, char c) void del_list(List
L, char c) void print_list(List L)
We want to write functions to insert a node to a
linked list, delete a node from a linked list,
and print all nodes in a linked list.
55Sample usage
include ltstdio.hgt include ltstdlib.hgt struct
Node char data Node next struct List
Node head void insert_list(List L,
char c) todo void del_list(List L, char
c) todo void print_list(List L) todo
int main () char c List L L.head
NULL print_list(L) insert_list(L, 'a')
insert_list(L, 'b') print_list(L)
del_list(L, c) printf("I just delete this
c\n", c) print_list(L) return 0
56Adding a node, 1
b
c
head
p
First, we prepare the new node.Node pp
(Node) malloc (sizeof(Node))p-gtdata 'a'
57Adding a node, 2
b
c
head
a
p
Then we connect the new node to the head of the
linked list. p-gtnext head
58Adding a node, 3
b
c
head
a
p
Finally, we update the head pointer. Now the
first node of the list is a. head p
Important Check whether this function works for
empty list.
59Deleting the first node, 1
b
c
a
head
First, we point a pointer p to the first node,
which will be deleted. Node p p head
60Deleting the first node, 2
b
c
a
head
p
Then we update the head pointer. Now it should
point to the second node in the original
list. head p-gtnext
61Deleting the first node, 3
b
c
head
Finally, you can free the node p after using
it. printf("c", p-gtdata) free(p) p NULL
Important Make sure your function can handle
list with a single node.
62Traversing a linked list, 1
b
c
a
head
We point p to the current node. After
processing, p is advanced to the next node. p
p-gtnext
63Traversing a linked list, 2
b
c
a
head
Start at the first node (pointed to by head).
Loop until p points to NULL.
p head while (p!NULL) printf("c",
p-gtdata) p p-gtnext
p head while (p) p p-gtnext
Important Make sure your code can handle empty
list.
64Program Listing, 1
include ltstdio.hgt include ltstdlib.hgt struct
Node char data Node next struct List
Node head
int main () char c List L L.head
NULL printf("\n\n") print_list(L)
insert_list(L, 'a') insert_list(L, 'b')
print_list(L) del_list(L, c) printf("I
just delete this c\n", c) print_list(L)
return 0
Put the following three functions here.
65Program Listing, 2
/ insert the char c to the head of the linked
list L / / !! no error checking for malloc
failure / void insert_list (List L, char c)
Node p p (Node) malloc(sizeof(Node))
p-gtdata c p-gtnext L-gthead L-gthead p
66Program Listing, 3
/ delete the first node of the linked list
and return the char stored there as c !! no
error checking for deleting from empty list
/ void del_list (List L, char c) Node p
p L-gthead L-gthead p-gtnext c
p-gtdata free(p) p NULL
67Program Listing, 4
/ prints the content of the linked list L
/ void print_list (List L) Node p p
L.head printf("The list contains ") while
(p!NULL) printf("c ", p-gtdata) p
p-gtnext printf("\n")
68Exercise
Q8) When malloc( ) cannot find enough memory, it
returns NULL. Add checking for this error in the
function insert_list( ). If there is not enough
memory, display an error message, abort the
insertion of data and return 0. Otherwise,
return 1 after successful insertion. int
insert_list (List L, char c)
69Exercise
Q9) User cannot delete a node from an empty
linked list in del_list ( ). Modify the function
to display an error message, abort deletion and
return 0 when the linked list is empty. Return 1
if deletion is successful and return the deleted
character through the parameter c. int del_list
(List L, char c) Q10) Write a function to
count and return the number of nodes in a linked
list. int count_list (List L)
70Modules
/ hello.cpp /include ltstdio.hgt void greet
(char s) printf("Hello s\n", s) void
goodbye ( ) printf("Bye bye") int main ()
greet("Peter") goodbye() return 0
Sometimes, your program might be getting too long
to fit in a single file. We can use modules to
extract some functions to a separate file.
71Need of Header
/ greet.cpp /include ltstdio.hgt void greet
(char s) printf("Hello s\n", s) void
goodbye ( ) printf("Bye bye")
Er.. What is greet( )?
/ hello.cpp / int main () greet("Peter")
goodbye() return 0
Splitting the program into two files raises two
problems. First, how does the main program know
the extracted functions greet( ) and goodbye ( )?
72Need of Project
/ greet.cpp /include ltstdio.hgt void greet
(char s) printf("Hello s\n", s) void
goodbye ( ) printf("Bye bye")
/ hello.cpp / int main () greet("Peter")
goodbye() return 0
hello.exe
Second, how do we tell the compiler that our
program consists of more than one files, namely
hello.cpp and greet.cpp?
73Header file
/ hello.cpp / int main () greet("Peter")
goodbye() return 0
/ greet.h / extern void greet (char s)extern
void goodbye()
/ greet.cpp /include ltstdio.hgt void greet
(char s) printf("Hello s\n", s) void
goodbye ( ) printf("Bye bye")
A solution to the first problem is to introduce
the extracted functions in a header file. We
then include the file in the main program.
74include
/ hello.cpp /include "greet.h" int main ()
greet("Peter") goodbye() return 0
/ hello.cpp /extern void greet (char
s)extern void goodbye() int main ()
greet("Peter") goodbye() return 0
/ greet.h / extern void greet (char s)extern
void goodbye()
The included statements list the signature of the
functions and tell the main program that the
functions are external,
75include
/ greet.h / extern void greet (char s)extern
void goodbye()
Although we dont need to do so, it is a good
practice to include the header in the module. It
helps to check that the signature of functions in
the header file is the same as those in the
module.
/ greet.cpp /include ltstdio.hgt include
"greet.h" void greet (char s) printf("Hello
s\n", s) void goodbye ( ) printf("Bye
bye")
76Project
/ hello.cpp /include "greet.h" int main ()
greet("Peter") goodbye() return 0
/ greet.h / extern void greet (char s)extern
void goodbye()
/ greet.cpp /include ltstdio.hgt include
"greet.h" void greet (char s) printf("Hello
s\n", s) void goodbye ( ) printf("Bye
bye")
To solve the second problem, we use project in
Turbo C. We tell the compiler that these two C
files form a single program by putting them in a
project. Detail will be given in demo in class.
77Module for Reuse
/ hello2.cpp /include "greet.h" int main ()
greet("Mary") greet("John") goodbye()
return 0
/ greet.h / extern void greet (char s)extern
void goodbye()
/ greet.cpp /include ltstdio.hgt include
"greet.h" void greet (char s) printf("Hello
s\n", s) void goodbye ( ) printf("Bye
bye")
In addition to keeping each source file shorter,
modules also help to reuse functions. stdio.h,
stdlib.h, string.h, etc.. are standard libraries
provided by the C compiler.