Brief Introduction to the C Programming Language
Object Oriented Programming Lab
Introduction
* The C programming language was designed by Dennis Ritchie at Bell Laboratories in the early 1970s
* Influenced by
o ALGOL 60 (1960),
o CPL (Cambridge, 1963),
o BCPL (Martin Richard, 1967),
o B (Ken Thompson, 1970)
* Traditionally used for systems programming, though this may be changing in favor of C++
* Traditional C:
o The C Programming Language, by Brian Kernighan and Dennis Ritchie, 2nd Edition, Prentice Hall
o Referred to as K&R
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Standard C
* Standardized in 1989 by ANSI (American National Standards Institute) known as ANSI C
* International standard (ISO) in 1990 which was adopted by ANSI and is known as C89
* As part of the normal evolution process the standard was updated in 1995 (C95) and 1999 (C99)
* C++ and C
o C++ extends C to include support for Object Oriented Programming and other features that facilitate large software development projects
o C is not strictly a subset of C++, but it is possible to write “Clean C” that conforms to both the C++ and C standards.
Elements of a C Program
* A C development environment includes
o System libraries and headers: a set of standard libraries and their header files. For example see /usr/include and glibc.
o Application Source: application source and header files
o Compiler: converts source to object code for a specific platform
o Linker: resolves external references and produces the executable module
* User program structure
o there must be one main function where execution begins when the program is run. This function is called main
+ int main (void) { ... },
+ int main (int argc, char *argv[]) { ... }
+ UNIX Systems have a 3rd way to define main(), though it is not POSIX.1 compliant
int main (int argc, char *argv[], char *envp[])
o additional local and external functions and variables
A Simple C Program
* Create example file: try.c
* Compile using gcc:
gcc –o try try.c
* The standard C library libc is included automatically
* Execute program
./try
* Note, I always specify an absolute path
* Normal termination:
void exit(int status);
o calls functions registered with atexit()
o flush output streams
o close all open streams
o return status value and control to host environment
/* you generally want to
* include stdio.h and
* stdlib.h
* */
#include
#include
int main (void)
{
printf(“Hello World\n”);
exit(0);
}
Source and Header files
* Just as in C++, place related code within the same module (i.e. file).
* Header files (*.h) export interface definitions
o function prototypes, data types, macros, inline functions and other common declarations
* Do not place source code (i.e. definitions) in the header file with a few exceptions.
o inline’d code
o class definitions
o const definitions
* C preprocessor (cpp) is used to insert common definitions into source files
* There are other cool things you can do with the preprocessor
Another Example C Program
example.c
/* this is a C-style comment
* You generally want to palce
* all file includes at start of file
* */
#include
#include
int
main (int argc, char **argv)
{
// this is a C++-style comment
// printf prototype in stdio.h
printf(“Hello, Prog name = %s\n”,
argv[0]);
exit(0);
}
/* comments */
#ifndef _STDIO_H
#define _STDIO_H
... definitions and protoypes
#endif
/usr/include/stdio.h
/* prevents including file
* contents multiple
* times */
#ifndef _STDLIB_H
#define _STDLIB_H
... definitions and protoypes
#endif
/usr/include/stdlib.h
#include directs the preprocessor
to “include” the contents of the file
at this point in the source file.
#define directs preprocessor to define macros.
Passing Command Line Arguments
* When you execute a program you can include arguments on the command line.
* The run time environment will create an argument vector.
o argv is the argument vector
o argc is the number of arguments
* Argument vector is an array of pointers to strings.
* a string is an array of characters terminated by a binary 0 (NULL or ‘\0’).
* argv[0] is always the program name, so argc is at least 1.
./try –g 2 fred
argc = 4,
argv =
‘t’‘r’‘y’‘\0’
argv:
[0]
[1]
[2]
[3]
[4] NULL
‘-’‘g’‘\0’
‘2’‘\0’
‘f’‘r’‘e’‘d’‘\0’
C Standard Header Files you may want to use
* Standard Headers you should know about:
o stdio.h – file and console (also a file) IO: perror, printf, open, close, read, write, scanf, etc.
o stdlib.h - common utility functions: malloc, calloc, strtol, atoi, etc
o string.h - string and byte manipulation: strlen, strcpy, strcat, memcpy, memset, etc.
o ctype.h – character types: isalnum, isprint, isupport, tolower, etc.
o errno.h – defines errno used for reporting system errors
o math.h – math functions: ceil, exp, floor, sqrt, etc.
o signal.h – signal handling facility: raise, signal, etc
o stdint.h – standard integer: intN_t, uintN_t, etc
o time.h – time related facility: asctime, clock, time_t, etc.
The Preprocessor
* The C preprocessor permits you to define simple macros that are evaluated and expanded prior to compilation.
* Commands begin with a ‘#’. Abbreviated list:
o #define : defines a macro
o #undef : removes a macro definition
o #include : insert text from file
o #if : conditional based on value of expression
o #ifdef : conditional based on whether macro defined
o #ifndef : conditional based on whether macro is not defined
o #else : alternative
o #elif : conditional alternative
o defined() : preprocessor function: 1 if name defined, else 0
#if defined(__NetBSD__)
Preprocessor: Macros
* Using macros as functions, exercise caution:
o flawed example: #define mymult(a,b) a*b
+ Source: k = mymult(i-1, j+5);
+ Post preprocessing: k = i – 1 * j + 5;
o better: #define mymult(a,b) (a)*(b)
+ Source: k = mymult(i-1, j+5);
+ Post preprocessing: k = (i – 1)*(j + 5);
* Be careful of side effects, for example what if we did the following
o Macro: #define mysq(a) (a)*(a)
o flawed usage:
+ Source: k = mysq(i++)
+ Post preprocessing: k = (i++)*(i++)
* Alternative is to use inline’ed functions
o inline int mysq(int a) {return a*a};
o mysq(i++) works as expected in this case.
Preprocessor: Conditional Compilation
* Its generally better to use inline’ed functions
* Typically you will use the preprocessor to define constants, perform conditional code inclusion, include header files or to create shortcuts
* #define DEFAULT_SAMPLES 100
* #ifdef __linux
static inline int64_t
gettime(void) {...}
* #elif defined(sun)
static inline int64_t
gettime(void) {return (int64_t)gethrtime()}
* #else
static inline int64_t
gettime(void) {... gettimeofday()...}
* #endif
Another Simple C Program
int main (int argc, char **argv) {
int i;
printf(“There are %d arguments\n”, argc);
for (i = 0; i < argc; i++) printf(“Arg %d = %s\n”, i, argv[i]); return 0; } * Notice that the syntax is similar to Java * What’s new in the above simple program? o of course you will have to learn the new interfaces and utility functions defined by the C standard and UNIX o Pointers will give you the most trouble Fred Kuhns () CSE332– Object Oriented Programming Lab * A variable declared as an array represents a contiguous region of memory in which the array elements are stored. int x[5]; // an array of 5 4-byte ints. * All arrays begin with an index of 0 * An array identifier is equivalent to a pointer that references the first element of the array o int x[5], *ptr; ptr = &x[0] is equivalent to ptr = x; * Pointer arithmetic and arrays: o int x[5]; x[2] is the same as *(x + 2), the compiler will assume you mean 2 objects beyond element x. Arrays and Pointers 0 1 2 3 4 1 0 2 3 little endian byte ordering memory layout for array x Fred Kuhns () CSE332– Object Oriented Programming Lab Pointers * For any type T, you may form a pointer type to T. o Pointers may reference a function or an object. o The value of a pointer is the address of the corresponding object or function o Examples: int *i; char *x; int (*myfunc)(); * Pointer operators: * dereferences a pointer, & creates a pointer (reference to) o int i = 3; int *j = &i; *j = 4; printf(“i = %d\n”, i); // prints i = 4 o int myfunc (int arg); int (*fptr)(int) = myfunc; i = fptr(4); // same as calling myfunc(4); * Generic pointers: o Traditional C used (char *) o Standard C uses (void *) – these can not be dereferenced or used in pointer arithmetic. So they help to reduce programming errors * Null pointers: use NULL or 0. It is a good idea to always initialize pointers to NULL. Fred Kuhns () CSE332– Object Oriented Programming Lab Pointers in C (and C++) Address 0x3dc 0x3d8 Program Memory 0x3cc 0x3c8 0x3c4 0x3c0 Note: The compiler converts z[1] or *(z+1) to Value at address (Address of z + sizeof(int)); In C you would write the byte address as: (char *)z + sizeof(int); or letting the compiler do the work for you (int *)z + 1; Step 1: int main (int argc, argv) { int x = 4; int *y = &x; int *z[4] = {NULL, NULL, NULL, NULL}; int a[4] = {1, 2, 3, 4}; ... 0x3bc 0x3b8 0x3b4 0x3b0 0x3d4 0x3d0 z[3] z[2] z[1] z[0] a[3] a[2] a[1] a[0] 4 0x3dc 0 0 0 0 4 3 2 1 NA NA x y Fred Kuhns () CSE332– Object Oriented Programming Lab Pointers Continued 4 0x3dc Address 0x3dc 0x3d8 Program Memory 0x3bc 0x3b8 0x3b4 0x3b0 0x3cc 0x3c8 0x3c4 0x3c0 Step 1: int main (int argc, argv) { int x = 4; int *y = &x; int *z[4] = {NULL, NULL, NULL, NULL}; int a[4] = {1, 2, 3, 4}; Step 2: Assign addresses to array Z z[0] = a; // same as &a[0]; z[1] = a + 1; // same as &a[1]; z[2] = a + 2; // same as &a[2]; z[3] = a + 3; // same as &a[3]; 0x3bc 0x3b8 0x3b4 0x3b0 4 3 2 1 NA 0x3d4 0x3d0 z[3] z[2] z[1] z[0] a[3] a[2] a[1] a[0] NA x y Fred Kuhns () CSE332– Object Oriented Programming Lab Pointers Continued 4 0x3dc Address 0x3dc 0x3d8 Program Memory 0x3bc 0x3b8 0x3b4 0x3b0 0x3cc 0x3c8 0x3c4 0x3c0 Step 1: int main (int argc, argv) { int x = 4; int *y = &x; int *z[4] = {NULL, NULL, NULL, NULL}; int a[4] = {1, 2, 3, 4}; Step 2: z[0] = a; z[1] = a + 1; z[2] = a + 2; z[3] = a + 3; Step 3: No change in z’s values z[0] = (int *)((char *)a); z[1] = (int *)((char *)a + sizeof(int)); z[2] = (int *)((char *)a + 2 * sizeof(int)); z[3] = (int *)((char *)a + 3 * sizeof(int)); 0x3bc 0x3b8 0x3b4 0x3b0 4 3 2 1 NA 0x3d4 0x3d0 z[3] z[2] z[1] z[0] a[3] a[2] a[1] a[0] NA x y Fred Kuhns () CSE332– Object Oriented Programming Lab Getting Fancy with Macros #define QNODE(type) \ struct { \ struct type *next; \ struct type **prev; \ } #define QNODE_INIT(node, field) \ do { \ (node)->field.next = (node); \
(node)->field.prev = \
&(node)->field.next; \
} while ( /* */ 0 );
#define QFIRST(head, field) \
((head)->field.next)
#define QNEXT(node, field) \
((node)->field.next)
#define QEMPTY(head, field) \
((head)->field.next == (head))
#define QFOREACH(head, var, field) \
for ((var) = (head)->field.next; \
(var) != (head); \
(var) = (var)->field.next)
#define QINSERT_BEFORE(loc, node, field) \
do { \
*(loc)->field.prev = (node); \
(node)->field.prev = \
(loc)->field.prev; \
(loc)->field.prev = \
&((node)->field.next); \
(node)->field.next = (loc); \
} while (/* */0)
#define QINSERT_AFTER(loc, node, field) \
do { \
((loc)->field.next)->field.prev = \
&(node)->field.next; \
(node)->field.next = (loc)->field.next; \
(loc)->field.next = (node); \
(node)->field.prev = &(loc)->field.next; \
} while ( /* */ 0)
#define QREMOVE(node, field) \
do { \
*((node)->field.prev) = (node)->field.next; \
((node)->field.next)->field.prev = \
(node)->field.prev; \
(node)->field.next = (node); \
(node)->field.prev = &((node)->field.next); \
} while ( /* */ 0)
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
typedef struct wth_t {
int state;
QNODE(wth_t) alist;
} wth_t;
#define QNODE(type) \
struct { \
struct type *next; \
struct type **prev; \
}
After Preprocessing and Compiling
typedef struct wth_t {
int state;
struct {
struct wth_t *next;
struct wth_t **prev;
} alist;
} wth_t;
state
next
prev
3 words in memory
0
0x00100
0x00104
0x100
head: instance of wth_t
0x104
0x108
memory layout after GCC
CPP
QNODE_INIT(head, alist)
#define QNODE_INIT(node, field) \
do { \
(node)->field.next = (node); \
(node)->field.prev = &(node)->field.next;\
} while ( /* */ 0 );
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
QNODE Manipulations
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
?
before
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
0x100
0
0x1a0
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QNODE Manipulations
before
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
0x100
0
0x1a0
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x104
node0
0x1a4
0x1a8
QNODE Manipulations
before
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x1a0
0x104
node0
0x1a4
0x1a8
QNODE Manipulations
before
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QNODE Manipulations
before
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head); \
} while (/* */0)
0x100
0
0x100
0x104
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node0, alist);
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QNODE Manipulations
before
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Adding a Third Node
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node1, alist);
0x200
0
0x200
0x204
node1
0x204
0x208
#define QINSERT_BEFORE(head, node, alist)\
do { \
*(head)->alist.prev = (node); \
(node)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node)->alist.next; \
(node)->alist.next = (head); \
} while (/* */0)
0x200
0
0x200
0x204
node1
0x204
0x208
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
Adding a Third Node
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node1, alist);
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x200
0x204
node1
0x204
0x208
#define QINSERT_BEFORE(head, node1, alist)\
do { \
*(head)->alist.prev = (node1); \
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)
0x200
0
0x200
0x204
node1
0x204
0x208
(1)
(1)
Adding a Third Node
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node1, alist);
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x200
0x204
node1
0x204
0x208
#define QINSERT_BEFORE(head, node1, alist)\
do { \
*(head)->alist.prev = (node1); \
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)
0x200
0
0x200
0x1a4
node1
0x204
0x208
(1)
(2)
(2)
Adding a Third Node
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node1, alist);
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x200
0x204
node1
0x204
0x208
#define QINSERT_BEFORE(head, node1, alist)\
do { \
*(head)->alist.prev = (node1); \
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)
0x200
0
0x200
0x1a4
node1
0x204
0x208
(1)
(1)
(2)
(2)
(3)
(3)
Adding a Third Node
0x100
0
0x1a0
0x1a4
head
0x104
0x108
0x1a0
0
0x100
0x104
node0
0x1a4
0x1a8
QINSERT_BEFORE(head, node1, alist);
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x200
0x204
node1
0x204
0x208
#define QINSERT_BEFORE(head, node1, alist)\
do { \
*(head)->alist.prev = (node1); \
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)
0x200
0
0x100
0x1a4
node1
0x204
0x208
(1)
(1)
(2)
(2)
(3)
(3)
(4)
(4)
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
0x100
0
??
??
head
0x104
0x108
0x1a0
0
??
??
node0
0x1a4
0x1a8
0x200
0
??
??
node1
0x204
0x208
#define QREMOVE(node, alist) \
do { \
(1) *((node)->alist.prev) = (node)->alist.next; \
(2) ((node)->alist.next)->alist.prev = (node)->alist.prev;\
(3) (node)->alist.next = (node); \
(4) (node)->alist.prev = &((node)->alist.next); \
} while ( /* */ 0)
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
#define QREMOVE(node, alist) \
do { \
*((node)->alist.prev) = (node)->alist.next; \
((node)->alist.next)->alist.prev = (node)->alist.prev;\
(node)->alist.next = (node); \
(node)->alist.prev = &((node)->alist.next); \
} while ( /* */ 0)
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
0
0x200
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
#define QREMOVE(node0, alist) \
do { \
(1) *((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0); \
(node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)
(1)
0x100
0
0x200
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x104
node1
0x204
0x208
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
#define QREMOVE(node0, alist) \
do { \
*((node0)->alist.prev) = (node0)->alist.next; \
(2) ((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0); \
(node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)
(2)
0x100
0
0x200
0x204
head
0x104
0x108
0x1a0
0
0x1a0
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x104
node1
0x204
0x208
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
#define QREMOVE(node0, alist) \
do { \
*((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(3) (node0)->alist.next = (node0); \
(node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)
(3)
0x100
0
0x200
0x204
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
0x200
0
0x100
0x104
node1
0x204
0x208
Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
#define QREMOVE(node0, alist) \
do { \
*((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0); \
(4) (node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)
(4)
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Solution to Removing a Node
0x100
0
0x1a0
0x204
head
0x104
0x108
0x1a0
0
0x200
0x104
node0
0x1a4
0x1a8
0x200
0
0x100
0x1a4
node1
0x204
0x208
QREMOVE(node0, alist);
0x100
0
0x200
0x204
head
0x104
0x108
0x1a0
0
0x1a0
0x1a4
node0
0x1a4
0x1a8
0x200
0
0x100
0x104
node1
0x204
0x208
#define QREMOVE(node, alist) \
do { \
(1) *((node)->alist.prev) = (node)->alist.next; \
(2) ((node)->alist.next)->alist.prev = (node)->alist.prev;\
(3) (node)->alist.next = (node); \
(4) (node)->alist.prev = &((node)->alist.next); \
} while ( /* */ 0)
Functions
* Always use function prototypes
int myfunc (char *, int, struct MyStruct *);
int myfunc_noargs (void);
void myfunc_noreturn (int i);
* C and C++ are call by value, copy of parameter passed to function
o C++ permits you to specify pass by reference
o if you want to alter the parameter then pass a pointer to it (or use references in C++)
* If performance is an issue then use inline functions, generally better and safer than using a macro. Common convention
o define prototype and function in header or name.i file
o static inline int myinfunc (int i, int j);
o static inline int myinfunc (int i, int j) { ... }
Basic Types and Operators
* Basic data types
o Types: char, int, float and double
o Qualifiers: short, long, unsigned, signed, const
* Constant: 0x1234, 12, “Some string”
* Enumeration:
o Names in different enumerations must be distinct
o enum WeekDay_t {Mon, Tue, Wed, Thur, Fri};
enum WeekendDay_t {Sat = 0, Sun = 4};
* Arithmetic: +, -, *, /, %
o prefix ++i or --i ; increment/decrement before value is used
o postfix i++, i--; increment/decrement after value is used
* Relational and logical: <, >, <=, >=, ==, !=, &&, ||
* Bitwise: &, |, ^ (xor), <<, >>, ~(ones complement)
Operator Precedence (from “C a Reference Manual”, 5th Edition)
15
16
Precedence
right-to-left
unary
address of
&
right-to-left
unary
indirection
(dereference)
*
right-to-left
unary
negation, plus
- +
right-to-left
unary
logical not
!
right-to-left
unary
bitwise not
~
right-to-left
prefix
increment, decrement
++ --
left-to-right
postfix
compound literal
(type){init}
left-to-right
postfix
increment, decrement
++ --
left-to-right
postfix
direct selection
.
left-to-right
postfix
function call
f(...)
left-to-right
postfix
subscripting
a[k]
size
indirect selection
simple tokens
Operator
n/a
primary
names,
literals
right-to-left
unary
sizeof
left to right
postfix
->
Associates
Class
Tokens
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Precedence
right-to-left
unary
casts
(type)
left-to-right
binary
multiplicative
* / %
left-to-right
binary
additive
+ -
sequential eval.
assignment
conditional
logical or
logical and
bitwise or
bitwise xor
bitwise and
equality/ineq.
relational
left, right shift
Operator
left-to-right
binary
,
right-to-left
binary
= += -=
*= /= %=
&= ^= |=
<<= >>=
right-to-left
ternary
?:
left-to-right
binary
||
left-to-right
binary
&&
left-to-right
binary
|
left-to-right
binary
^
left-to-right
binary
&
left-to-right
binary
== !=
left-to-right
binary
< <= > >=
left-to-right
binary
<< >>
Associates
Class
Tokens
Structs and Unions
* structures
o struct MyPoint {int x, int y};
o typedef struct MyPoint MyPoint_t;
o MyPoint_t point, *ptr;
o point.x = 0;point.y = 10;
o ptr = &point; ptr->x = 12; ptr->y = 40;
* unions
o union MyUnion {int x; MyPoint_t pt; struct {int 3; char c[4]} S;};
o union MyUnion x;
o Can only use one of the elements. Memory will be allocated for the largest element
Conditional Statements (if/else)
if (a < 10) printf(“a is less than 10\n”); else if (a == 10) printf(“a is 10\n”); else printf(“a is greater than 10\n”); * If you have compound statements then use brackets (blocks) o if (a < 4 && b > 10) {
c = a * b; b = 0;
printf(“a = %d, a\’s address = 0x%08x\n”, a, (uint32_t)&a);
} else {
c = a + b; b = a;
}
* These two statements are equivalent:
o if (a) x = 3; else if (b) x = 2; else x = 0;
o if (a) x = 3; else {if (b) x = 2; else x = 0;}
* Is this correct?
o if (a) x = 3; else if (b) x = 2;
else (z) x = 0; else x = -2;
Conditional Statements (switch)
int c = 10;
switch (c) {
case 0:
printf(“c is 0\n”);
break;
...
default:
printf(“Unknown value of c\n”);
break;
}
* What if we leave the break statement out?
* Do we need the final break statement on the default case?
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Loops
* flow control
o break – exit innermost loop
o continue – perform next iteration of loop
* Note, all these forms permit one statement to be executed. By enclosing in brackets we create a block of statements.
for (i = 0; i < MAXVALUE; i++) {
dowork();
}
while (c != 12) {
dowork();
}
do {
dowork();
} while (c < 12);
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Building your program
* For all labs and programming assignments:
o you must supply a make file
o you must supply a README file that describes the assignment and results. This must be a text file, no MS word.
o of course the source code and any other libraries or utility code you used
o you may submit plots, they must be postscript or pdf
make and Makefiles, Overview
* Why use make?
o convenience of only entering compile directives once
o make is smart enough (with your help) to only compile and link modules that have changed or which depend on files that have changed
o allows you to hide platform dependencies
o promotes uniformity
o simplifies my (and hopefully your) life when testing and verifying your code
* A makefile contains a set of rules for building a program
target ... : prerequisites ...
command
...
* Static pattern rules.
o each target is matched against target-pattern to derive stem which is used to determine prereqs (see example)
targets ... : target-pattern : prereq-patterns ...
command
...
Makefiles
* Defining variables
MyOPS := -DWTH
MyDIR ?= /home/fred
MyVar = $(SHELL)
* Using variables
MyFLAGS := $(MyOPS)
* Built-in Variables
o $@ = filename of target
o $< = name of the first prerequisites
* Patterns
o use % character to determine stem
o foo.o matches the pattern %.o with foo as the stem.
o foo.o moo.o : %.o : %.c # says that foo.o depends on foo.c and moo.o depends on moo.c
Fred Kuhns ()
CSE332– Object Oriented Programming Lab
Example Makefile for wulib
# Project specific
include ../Makefile.inc
INCLUDES = ${WUINCLUDES} –I.
LIBS = ${WILIBS} ${OSLIBS}
CFLAGS = ${WUCLFAGS} –DWUDEBUG
CC = ${WUCC}
HDRS := util.h
CSRCS := testapp1.c testapp2.c
SRCS := util.c callout.c
COBJS = $(addprefix ${OBJDIR}/, \
$(patsubst %.c,%.o,$(CSRCS)))
OBJS = $(addprefix ${OBJDIR}/, \
$(patsubst %.c,%.o,$(SRCS)))
CMDS = $(addprefix ${OBJDIR}/, $(basename $(CSRCS)))
all : $(OBJDIR) $(CMDS)
install : all
$(OBJDIR) :
mkdir $(OBJDIR)
$(OBJS) $(COBJS) : ${OBJDIR}/%.o : %.c $(HDRS)
${CC} ${CFLAGS} ${INCLUDES} –o $@ -c $<
$(CMDS) : ${OBJDIR}/% : ${OBJDIR}/%.o $(OBJS)
${CC} ${CFLAGS} -o $@ $@.o ${LIBS}
chmod 0755 $@
clean :
/bin/rm -f $(CMDS) $(OBJS)
# Makefile.inc
# Contains common definitions
MyOS := $(shell uname -s)
MyID := $(shell whoami)
MyHost := $(shell hostname)
WARNSTRICT := -W \
-Wstrict-prototypes \
-Wmissing-prototypes
WARNLIGHT := -Wall
WARN := ${WARNLIGHT}
ALLFLGS := -D_GNU_SOURCE \
-D_REENTRANT \
-D_THREAD_SAFE
APPCFLGS = $(ALLFLGS) \
$(WARN)
WUCC := gcc
WUCFLAGS := -DMyOS=$(MyOS) \
$(OSFLAGS) \
$(ALLFLGS) $(WARN)
WUINCLUDES :=
WULIBS := -lm
ifeq (${MyOS), SunOS)
OSLIBS+= -lrt
endif
Leia Mais...