Spring 2013: CSE2421 Systems1
Spring 2013: CSE2421 Systems1
CSE2421 Systems1
Introduction to Low-Level Programming and Computer Organization
Kitty Reeves
TWRF 8:00-8:55am
1
Linked List Node structure
A linked list is…
a dynamic data structure consisting of a group of nodes which
together represent a sequence and whose length can be increased
or decreased at run time
Simply, each node is composed of a data and a reference (in other
words, a link) to the next node in the sequence
Allows for efficient insertion or removal of elements from any
position in the sequence (vs an array).
Data items need not be stored contiguously in memory
Major Disadvantage:
does not allow random access to the data or any form of efficient
indexing
/* Node Structure */
struct node { A linked list whose nodes contain two fields: an
int data; integer value and a link to the next node. The last
node is linked to a terminator used to signify the end
struct node *next; }
of the list.
2
Linked List stack and heap
Each node is allocated in the heap with a call to malloc(), so the node
memory continues to exist until it is explicitly deallocated with a call to
free().
3
Build {1,2,3} linked list
/* Build the list {1, 2, 3} in the heap and store its head pointer in a local stack
variable. Returns the head pointer to the caller. */
struct node* BuildOneTwoThree() {
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
// allocate 3 nodes in the heap
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 1; // setup first node
head->next = second; // note: pointer assignment rule
second->data = 2; // setup second node
second->next = third;
third->data = 3; // setup third link
third->next = NULL;
// At this point, the linked list referenced by "head“ matches the list in the drawing.
return head; }
4
Linked List example
#include<stdlib.h>
#include<stdio.h>
What does this do?
struct list_el {
int val;
struct list_el * next; };
typedef struct list_el item;
void main() {
item * curr, * head;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *) malloc(sizeof(item));
curr->val = i;
curr->next = head;
head = curr; }
curr = head;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ; }
}
5
Linked list basics
The first node is always made accessible through a
global ‘head’ pointer.
This pointer is adjusted when first node is deleted.
Similarly there can be an ‘end’ pointer that contains
the last node in the list.
This is also adjusted when last node is deleted.
The last node in a list always has a NULL value so you
don’t *have* to keep track of the end of the list, just
check for a NULL pointer.
Whenever a node is added to linked list, it is always
checked if the linked list is empty then add it as the
first node.
You can pass the list by passing the head pointer.
6
Linked List setup
ptr end (optional)
NODE structure
head data data data data
next next next next=NULL
NEED TO:
Allocate a new node structure with DMA
(dynamic memory allocation) new
7
Linked List ADD/DELETE node
OPERATION FRONT END MIDDLE
new->next = head ptr->next = new new->next = ptr->next
INSERT
head = new new->next = NULL ptr-> next= new
found = false;
ptr = head;
while(ptr != NULL) //what if nothing in list?
SEARCH
{ if(ptr->data = = val) // found what searching for
{ found = true;
break; }
else { ptr = ptr->next; }
} // if found still false, didn’t find
//if ptr->next=NULL
DELETE head = ptr->next prev = ptr prev->next = ptr->next
(fyi: free ptr) // what if only node?
prev->next = NULL
8
Link list pictorial view - INSERT
Inserting into a link list has
two cases
First in the list
Not first in the list
If going at head, modify head
reference (only)
If going elsewhere, need
reference to node before
insertion point
New node.next = cur
node.next
Cur node.next = ref to new
node
Must be done in this order!
9
Link list pictorial view - DELETE
Deleting a link list has two
cases
First in the list
Not first in the list
If deleting from head,
modify head reference
(only)
If deleting elsewhere,
simply “point around” the
deleted node
Be sure to free the deleted
nodes
10
Link list pictorial view - TRAVERSE
Start at the head
Use a “current” reference for
the current node
Use the “next” reference to
find the next node in the list
Repeat this to find the
desired node
N times to find the nth node
Until the object matches if
looking for a particular object
Caution: objects can “match”
even if the references aren’t the
same…
Don’t forget to check to see if
this is the last node
11
Linked List operations
Initialize the list void InitList(struct list *sList);
Push/Insert a value onto the list
Search the list /* Initializes the list structure */
Pop/Remove a value off of the list void InitList(struct list *sList) {
Print the list sList->start = NULL; }
void push(struct list *sList, int data); void pop(struct list *sList)
/* Adds a value to the front of the list */ /* Removes the first value of the list */
void push(struct list *sList, int data) { void pop(struct list *sList) {
struct node *p; if(sList->start != NULL) {
p = malloc(sizeof(struct node)); struct node *p = sList->start;
p->data = data; sList->start = sList->start->next;
p->next = sList->start; free(p); } }
sList->start = p; }
(see linklst2.c)
12
Double Linked List (DLL)
A more sophisticated form of a
linked list data structure.
Each node contains a value, a
link to the next node (if any)
and a link to the previous node
(if any)
The header points to the first
node in the list and to the last
node in the list (or contains null
links if the list is empty
myDLL
a b c
13
DLLs compared to SLLs
Advantages:
Can be traversed in either direction (may be
essential for some programs)
Some operations, such as deletion and inserting
before a node, become easier
Disadvantages:
Requires more space
List manipulations are slower (because more
links must be changed)
Greater chance of having bugs (because more
links must be manipulated)
14
Double linked list – INSERT
As with singly linked lists,
special case for head
Also special case for tail
Need to update two nodes
Node before new node
Node after new node
Hook up new node before
modifying other nodes
Don’t overwrite necessary
information before relocating it!
Head & tail: if a link is null,
update the head or tail as
appropriate
15
Deleting a node from a DLL
Node deletion from a DLL involves changing two
links
In this example,we will delete node b
myDLL
a b c
16
Double linked list - DELETE
As with singly linked lists,
special case for head
Also special case for tail
Need to update two nodes
Node before new node
Node after new node
Hook up new node before
modifying other nodes
Don’t overwrite necessary
information before relocating
it!
Head & tail: if a link is null,
update the head or tail as
appropriate
17
Other operations on linked lists
Most “algorithms” on linked lists—such as
insertion, deletion, and searching—are pretty
obvious; you just need to be careful
Sorting a linked list is just messy, since you
can’t directly access the nth element—you
have to count your way through a lot of other
elements
18
Double linked lists - SETUP
//DECLARATIONS /* The following function initializes
the linked list by putting zeros into
/* The type link_t needs to be forward- the pointers containing the first and
declared in order that a self-reference last links of the linked list. */
can be made in "struct link" below. */ static void
typedef struct link link_t; linked_list_init (linked_list_t * list)
{ list->first = list->last = 0; }
/* A link_t contains one of the links of
the linked list. */
struct link {
const void * data;
link_t * prev;
link_t * next; };
22
Bitwise Operations
Many situations need to operate on the bits
of a data word –
Register inputs or outputs
Controlling attached devices
Obtaining status
Corresponding bits of both operands are
combined by the usual logic operations.
Apply to all kinds of integer types
Signed and unsigned
char, short, int, long, long long
23
Bitwise Operations (cont)
• & – AND • ~ – Complement
• Result is 1 if both • Each bit is reversed
operand bits are 1
• | – OR • << – Shift left
• Result is 1 if either • Multiply by 2
operand bit is 1
• ^ – Exclusive OR • >> – Shift right
• Result is 1 if operand • Divide by 2
bits are different
24
Examples
a 1 1 1 1 0 0 0 0 NOTE: when signed all the same
FYI: integers are really 32 bits so what is the “real” value?
b 1 0 1 0 1 0 1 0 ~a has preceding 1’s and a<<2 is 0x 3c0
unsigned int c, a, b;
c = a & b; // 1010 0000
c = a | b; // 1111 1010
c = a ^ b; // 0101 1010
c = ~a // 0000 1111
c = a << 2; // 1100 0000
c = a >> 3; // 0001 1110
25
Bitwise AND/OR
char x = ‘A’; char y = ‘a’;
tolower(x) returns ‘a’… HOW? toupper(y) returns ‘A’… HOW?
‘A’ = 0x41 = 0100 0001
‘a’ = 0x61 = 0110 0001
“mask” = 0010 0000 “mask” = 1101 1111
Use OR Use AND
0100 0010
0000 1010 XOR (toggle)
0100 1000
27
Bitwise left/right shifts
Possible overflow issues
Exact behavior is implementation dependent
When you shift left by k bits ==
multiplying by 2K
28
Bitwise right shifts
a 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 b 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
unsigned int c, a;
c = a >> 3; c 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0
signed int c, a, b;
c = b >> 3; c0 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
c = a >> 3; c 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0
29
C example…
#include <stdio.h>
void main()
{
signed int c, d, a, b, e, f; Output is:
a = 0xF0F0;
b = 0x5555; b >> 3 is aaa
e = 0b01000001;
f = 'A'; a >> 3 is 1e1e
c = b >> 3;
binary = 41
d = a >> 3; char a = A
printf("b >> 3 is %x\n",c);
printf("a >> 3 is %x\n",d);
printf("binary = %x\n",e);
printf("char a = %c",f);
}
30
Bit example exceptions
#include <stdio.h> % gcc -o bitex bitex.c
void main() bitex.c: In function ‘main’:
bitex.c:11: warning: right shift count >= width of type
{ int a, b, c, d, e, f; bitex.c:12: warning: right shift count is negative
a = 0xF0F0F0F0; bitex.c:21: warning: left shift count >= width of type
b = 0x55555555; bitex.c:22: warning: left shift count is negative
c = a >> 3; // repeats sign bit of 1
d = b >> 3; // repeats sign bit of 0
e = a >> 35; // 35(k) % 32(w) but technically undefined
f = b >> -3; // 32(w) - 3(k) but technically undefined % bitex
printf("a >> 3 is %.8x\n",c); a >> 3 is fe1e1e1e
printf("b >> 3 is %.8x\n",d); b >> 3 is 0aaaaaaa
printf("a >> 35 is %.8x\n",e); a >> 35 is fe1e1e1e
printf("b >> -3 is %.8x\n",f); b >> -3 is 00000002
printf("a << 3 is %.8x\n",a << 3); a << 3 is 87878780
printf("b << 3 is %.8x\n",b << 3); b << 3 is aaaaaaa8
printf("a << 35 is %.8x\n",a << 35); a << 35 is 87878780
printf("b << -3 is %.8x\n",b << -3); b << -3 is a0000000
}
31
Traditional Bit Definition
8-bit Printer Status Register
#define EMPTY 01
#define JAM 02
#define LOW_INK 16
#define CLEAN 64
char status;
if (status == (EMPTY | JAM)) ...;
if (status == EMPTY || status == JAM) ...;
while (! status & LOW_INK) ...;
32
Traditional Bit Definitions
Used very widely in C
Including a lot of existing code
No checking
You are on your own to be sure the right bits are set
Machine dependent
Need to know bit order in bytes, byte order in words
Integer fields within a register
Need to AND and shift to extract
Need to shift and OR to insert
33
Int main(with arguments)
Options:
int main(void);
int main();
int main(int argc, char **argv);
int main(int argc, char *argv[]);
34
int main(argc, *arv[])
The name of the program, argv[0], may be useful
when printing diagnostic messages
The individual values of the parameters can be
accessed:
*argv[] also seen as **argv
argc argv
4 myFilt\0
p1\0
p2\0
p3\0
Array of pointers where each
element is a pointer to a character …
35
Command Line Arguments
It is guaranteed that argc is non-negative and
that argv[argc] is a null pointer.
By convention, the command-line arguments
specified by argc and argv include the name of
the program as the first element if argc is greater
than 0
For example, if a user types a command of "rm
file", the shell will initialize the rm process with
argc = 2 and argv = ["rm", "file", NULL]
The main() function is special; normally every C
program must define it exactly once.
36
CLA - Example 1
#include <stdio.h>
int main(int argc, char *argv[]) {
if ( argc != 3)
printf("Usage:\n %s Integer1 Integer2\n",argv[0]);
else
// ascii to integer
printf("%s + %s = %d\n",argv[1],argv[2], atoi(argv[1])+atoi(argv[2]));
return 0;
}
37
CLA – Example 2
#include <stdio.h> Rewrite the
#include <stdlib.h> program which
main( int argc, char *argv[]) copies files, ie,
{ FILE *in_file, *out_file, *fopen(); FCOPY.C to accept
int c; the source and
if( argc != 3 ) { destination
printf("Incorrect, format is FCOPY source dest\n"); filenames from the
exit(2); } command line.
in_file = fopen( argv[1], "r"); Include a check on
if( in_file == NULL ) the number of
printf("Cannot open %s for reading\n", argv[1]); arguments passed.
else { out_file = fopen( argv[2], "w");
if ( out_file == NULL )
printf("Cannot open %s for writing\n", argv[2]);
else { printf("File copy program, copying %s to %s\n", argv[1], argv[2]);
while ( (c=getc( in_file) ) != EOF )
putc( c, out_file );
putc( c, out_file); /* copy EOF */
printf("File has been copied.\n"); fclose( out_file); } fclose( in_file); } }
38
Redirection File I/O
Part of the operating system (linux)
% lab2p2file < lab2p2in >! lab2p2out
! overwrites if the file already exists
input = 0; Input File:
War_Eagle!
scanf(…, input); How_many_WORDS_workhere?
while (input != 0) i
{ loop stuff… $hake_u_r_booty:)_!
Og_sbuCk!!!
input = 0; REALLy_really_really_really___really_long??!!_
scanf(…, input); Hi.01234_How_R_U_?
} |
39
Header and Makefile example
Start here
40
What is happening?
The -c option on the gcc command only
compiles the files listed
Once all 3 C files are correctly compiled, then
using gcc with the -o option allows object
files (notice the .o extensions) to be merged
into one executable file.
Notice where all “mkfunc.h” is included
41
Library includes
The compiler supports two different types of
#includes
Library files
Local files
#include <filename>
#include “filename”
42
Creating header files
In our case, be sure to save your header file in a
‘directory where you are going to save the program’
(NOTE: This is important. Both the header file and the
program must be in the same directory, if not the
program will not be able to detect your header file ).
43
Makefile Overview
Makefiles are a UNIX thing, not a programming language thing
Makefiles contain UNIX commands and will run them in a specified
sequence.
You name of your makefile has to be: makefile or Makefile
The directory you put the makefile in matters!
You can only have one makefile per directory.
Anything that can be entered at the UNIX command prompt can
be in the makefile.
Each command must be preceded by a TAB and is immediately
followed by hitting the enter key
MAKEFILES ARE UNFORGIVING WHEN IT COMES TO WHITESPACE!
To execute… must be in the directory where the makefile is:
% make tag-name (also called section name)
44
Makefile Details
Compiling our example would look like:
gcc -o mkhello mkmain.c mkhello.c mkfact.c
OR
gcc mkmain.c mkhello.c mkfact.c -o mkhello
45
Makefile dependencies
Useful to use different targets
Because if you modify a single project, you don’t have to
recompile everything, only what you modified
46
Why use OOP in general?
The concepts and rules used in object-oriented
programming provide these important benefits:
The concept of data classes allows a programmer to create any
new data type that is not already defined in the language itself
(typedef).
The concept of a data class makes it possible to define
subclasses of data objects that share some or all of the main
class characteristics. Called inheritance, this property of OOP
forces a more thorough data analysis, reduces development
time, and ensures more accurate coding.
Since a class defines only the data it needs to be concerned
with, when an instance of that class (an object) is run, the
code will not be able to accidentally access other program
data. This characteristic of data hiding (i.e. encapsulation)
provides greater system security and avoids unintended data
corruption.
47
WHY use OOP in general (cont)?
Facilitates utilizing and creating reusable
software components
The definition of a class is reuseable not only by the
program for which it is initially created but also by other
object-oriented programs (and, for this reason, can be
more easily distributed for use in networks).
Better suited for team development
Easier software maintenance
48
OOP simple review
• Class
• A software construct that abstractly models something
• Defines a structure to hold some sort of state
• Defines operations that mutate or recall this state
somehow
• Object
• A specific instance of a Class
• Holds the state representing a particular instance of the
Class
• Examples:
• Class – Person
• Instance – William Gates
49
OOP simple review (cont)
Define method (~function)
To emulate member functions, you can put function pointers
in structs.
Define inheritance
a way to reuse code of existing objects, or to establish a
subtype from an existing object, or both, depending upon
programming language support
Define polymorphism
the ability to create a variable, a function, or an object that has
more than one form
allows values of different data types to be handled using a
uniform interface (malloc returns void type)
Encapsulation == information hiding
C has language support for private encapsulation of both
variables and functions, through the static keyword
50
Porting object-oriented concepts to C
It's possible to create object-oriented like code in C, which
is very useful for mimicking standard libraries and objects
found in OOPs
Ex. Stack and Queue classes with push/pop methods =
functions - the basis for modular structured programming in C.
Header files = Use to define global constants and variables
Take a class design from what would be standard OOP,
retain strictly only member variables, and move them to a
struct.
Within global space, create functions that take a pointer to
a related struct instance and manipulate accordingly. For
every instance of the object, only use the related functions
instead of directly accessing the data. This is to mimic the
data hiding found in OOPs.
51
Features of OOC
Encapsulation and data hiding (can be achieved using
structs/opaque pointers)
Inheritance and support for polymorphism (single inheritance can
be achieved using structs - make sure abstract base is not
instantiable)
Constructor and destructor functionality (not easy to achieve)
Type checking (at least for user defined types as C doesn't enforce
any)
Instead of passing pointers to structs, you end up passing pointers
to pointers to structs. This makes the content opaque and
facilitates polymorphism and inheritance. The real problem with
OOP in C is what happens when variables exit scope. There's no
compiler generated destructors and that can cause issues.
MACROS can possibly help but it is always going to be ugly to look
at.
52
Class
The basic idea of implementing a class in C is
to group the data for a C object into structs so
that you can have any number of objects. The
struct is declared in the .h file so that it is
shared between the class and its clients. In
addition, you usually need a function that
initializes the objects in the class.
53
Methods
If you think of methods called on objects as
static methods that pass an implicit 'this' into
the function it can make thinking OO in C
easier.
For example:
String s = "hi";
System.out.println(s.length());
becomes:
string s = "hi";
printf(length(s)); // pass in s, as an implicit this
54
Objects
At the most basic level, you just use plain structs
as objects and pass them around by pointers.
struct monkey
{
float age;
bool is_male;
int happiness;
};
55
Opaque Pointers
An opaque pointer is a special case of an opaque data type, a data
type declared to be a pointer to a record or data structure of some
unspecified type.
Opaque pointers are a way to hide the implementation details of
an interface from ordinary clients, so that the implementation may
be changed without the need to recompile the modules using it.
This benefits the programmer as well since a simple interface can
be created, and most details can be hidden in another file.
This example demonstrates a way to achieve the information
hiding (encapsulation) aspect of Object-Oriented Programming
using the C language. If someone wanted to change the
declaration of struct obj, it would be unnecessary to recompile any
other modules in the program that use the obj.h header file unless
the API was also changed.
56
Opaque /* obj.c */
Pointer #include "obj.h"
struct obj {
example int id; };
59
Vtables and polymorphism
You can implement polymorphism with regular
functions and virtual tables (vtables)
60
Inheritance
To get things like inheritance You can do manual
and polymorphism, you have inheritance by
to work a little harder. having the first
member of a
struct base structure be an
{ instance of the
/* base class members */
}; superclass, and
struct derived then you can cast
{ around pointers to
struct base super; base and derive
/* derived class members */ classes freely
};
struct derived d;
struct base *base_ptr = (struct base *)&d; // upcast
struct derived derived_ptr = (struct derived *)base_ptr; // downcast
61
Define object then inherit
Each object has its own file.
Public functions and variables are defined in the .h file for an object.
Private variables and functions were only located in the .c file.
To "inherit“, a new struct is created with the first member of the struct
being the object to inherit from.
Inheriting is difficult to describe, but basically it was this:
struct vehicle { int power; int weight; }
Then in another file:
struct van { struct vehicle base; int cubic_size; }
Then you could have a van created in memory, and being used by code
that only knew about vehicles:
struct van my_van;
struct vehicle *something = &my_van;
vehicle_function( something );
It worked beautifully, and the .h files defined exactly what you should be
able to do with each object.
62
OOC Example
#include "triangle.h" Output:
#include "rectangle.h" 6.56 This is real, pure C, no preprocessor
#include "polygon.h" 13.12 macros. We have inheritance,
#include <stdio.h> polymorphism and data
encapsulation (including data
private to classes or objects). There
int main() { is no chance for protected qualifier
Triangle tr1= CTriangle->new(); equivalent, that is, private data is
Rectangle rc1= CRectangle->new(); private down the inheritance chain
too; but not an inconvenience
because not necessary.
tr1->width= rc1->width= 3.2;
tr1->height= rc1->height= 4.1;
CPolygon is not instantiated because
CPolygon->printArea((Polygon)tr1); we only use it to manipulate objects
of down the innheritance chain that
have common aspects but different
printf("\n"); implementation of them
(Polymorphism)
CPolygon->printArea((Polygon)rc1); }
63