Download presentation
Presentation is loading. Please wait.
Published byRalph Ross Modified over 8 years ago
1
Low-level programming using C Programming in assembly lang. is a real nuisance … But in some situations such as implementing device drivers or OS functions, we need to be close to the machine level … Solution: C Often called a “high-level assembly lang.” but that is misleading … once you get used to it, you can write good code in it 1 CSE 3430; Part 5
2
C Bit of history: When C++ was introduced, the goal was to introduce the notion of “classes” into C; so it was originally called “C with classes” In a real sense, C = C++, less classes But that is incorrect: effective C programming is special skill … we will try to get some of it Best reference: The C Programming Language, Kernighan and Ritchie (aka “K&R” book) 2 CSE 3430; Part 5
3
3 Program to count lines, words, characters. A word is any seq. of characters w/o whitespace #include #define IN 1/* inside a word */ #define OUT 0/* outside a word */ main() { int c, nl, mw, nc, state; state = OUT; nl = nw = nc = 0; while ((c = getchar()) != EOF) { ++nc; if (c == ‘\n’) ++nl; if (c==‘ ‘ || c==‘\n’ || c==‘\t’) state = OUT; else if (state == OUT) { state = IN; ++nw; } printf(“%d %d %d\n”, n, nw, nc); Some C Programs Important notes: Lines starting with “#”: for pre-processor getchar(), printf() specified in nl = nw = nc = 0 : nl = (nw = (nc = 0)) Syntax in the while-cond. is often used to avoid unintended effects ++nc vs. nc++ printf() fairly useful, has many options
4
Some key features of C Basic types: char, int, float, double Also pointer variables to specific type: int* Y caution: int* Y, Z is not what you think! Arrays are also allowed … but an array such as: char X[100] introduces a (const) pointer variable X and 100 bytes with X containing address of first (0th) byte More as we go along Parameters are passed by value So: often have to use pointer types as parameters … that is what happens when you pass an array 4 CSE 3430; Part 5
5
Read a set of text lines and print the longest #include #define MXLNGTH 1000 /*uppercase convention*/ void copy(char to[], char from[]); /*prototype; also: these are ptrs*/ int getline(char line[], int ml); main() { int len; //current line length int max; // longest so far char line[MXLNGTH]; //current line char longest[MXLNGTH]; //longest seen max = 0; while ((len=getline(line,MXLNGTH) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) printf(“%s”, longest); return 0; } Another C program void copy(char to[]. char from[]) { int i; i = 0; while ((to[i] = from[i]) != ‘\0’) ++i; } int getline(char s[], int lim) { int c, i; for (i=0; i<lim-1 && (c=getchar())!=EOF && c!=‘\n’; ++i) s[i] = c; if (c == ‘\n’) { s[i] = c; ++i; } s[i] = ‘\0’; return i; } int strlen(char s[]) { int i; i = 0; while (s[i] != ’\0’) ++i; return i; } 5
6
6 More C programs int atoi(char s[]) {/*conv s to integer*/ int i, n; for (i=0; s[i] >= '0' && s[i] <= '9'; ++i) n = 10 * n + (s[i] – '0'); return n; } int lower (int c) {/*conv c to l.c.*/ if (c >= 'A' && c <= 'Z') return (c + 'a' – 'A'); else return c; /*return ((c >= 'A' && c <= 'Z') ? (c + 'a' – 'A') : c ); */ } int atoi(char s[]) {/*conv s to integer*/ /* see p. 61 of book for more general version */ } #include void printd(int n) { // print n in decimal if (n < 0) { putchar('-'); n = -n; } if (n / 10) printd(n /10); putchar(n % 10 + '0'); } void swap(int v[], int i, int j); // v[i] ↔ v[j] // qsort: sort v[left] … v[r] in incr. order void qsort(int v[], int left, int right) { int i, last; if (left >= right) return; // less than 2 elmts swap(v, left, (left+right)/2); //move part. last = left; //elmt to v[left] for (i=left+1; i <= right; i++)// partition if (v[i] < v[left]) swap(v, ++last, i); swap(v, left, last); // restore partition elmt qsort(v, left, last-1); qsort(v, last+1, right); } void swap(int v[], int i, int j) { int temp; temp = v[i]; v[i] = v[j]; v[j] = temp; }
7
7 C Pointers int x, y; x = 1; y = 2; int *ip; // int* ip is ok but not "int* ip, iq" ip = &x; y = *ip; *ip = 0; // y==1, x==0 *ip = *ip+10; // same as x = x+10 void swap(int p, int q) { // won't work int temp; temp = p; p = q; q = temp; // won't }//work as p, q are local variables // strong correlation bet. ptrs & arrays // int x[10]: allocates 10 int locations // *and* a ptr. var. x whose value is // address of x[0] int *px; int x[10]; px = x; // same as px = &x[0] // in effect x, px are same but … px++; // will have addr of x[1] in px x++; // **illegal**; x is a *constant* Pointers play a very important role in C … you haven't "got C" until you are comfortable with using pointers int strlen(char *s) { int n; for (n=0; *s != '\0'; s++) n++; return n; } strlen("hello, world");// string constant strlen(ca); // char ca[100] strlen(pc); // char *pc … all work As formal parameters: "char s[]" same as "char *s" but latter is better since s really a ptr strlen(&ca[5]); // works properly… but not strlen(c[5]); // why not? void swap(int *p, int *q) { //not int* p, q! int temp; temp = *p; *p = *q; *q = temp; }//call: swap(&x, &y)
8
8 C Pointers (contd) void strcpy(char *s, char *t) { int i; i = 0; while ((s[i] = t[i]) != '\0') i++; } Ptrs to arrays of char are expecially useful and common but remember: "char *s" MEANS s can point to an array of char's, not just one void strcpy(char *s, char *t) { while ((*s = *t) != '\0') {//ptr version s++; t++; } // better: void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0'); } //guru version!: void strcpy(char *s, char *t) { while (*s++ = *t++) ; } int strcmp(char *s, char *t) { //array version int i; // returns 0, neg., or pos. number for (i=0; s[i]==t[i]; i++) if (s[i] == '\0') return 0; return (s[i] – t[i]); } int strcmp(char *s, char *t) { //ptr version for ( ; *s == *t; s++, t++ ) // ',' expression if (*s == '\0') return 0; return ( *s – *t ); }
9
9 C Pointers (contd) (skip?) Since pointers are variables, they (i.e., their values) can be stored in arrays; so we can have an array of three char* ptrs, the three elements pointing to "abcd", "efg", "xyzabc" //from p. 108-110 of K & R: really nice! // task: read lines; sort them; print them // key: modify qsort to sort array of strings // void qsort(int v[], int left, int right) { void qsort(char *v[], int left, int right) { //v is an array of ptrs to char (so strings) // *only change*: replace: if (v[i] < v[left]) swap(v, ++last, i); // by if (strcmp(v[i],v[left]) < 0) swap(…) //that's it! Also need to modify swarp() to have, as parameters two pointers to strings Important: swap does NOT copy the strings; just exchanges the pointers void swap(char* v[], int i, int j) { char* temp; temp = v[i]; v[i] = v[j]; v[j] = temp; }
10
10 More C programs When main() begins, it gets two arguments: argc and argv; for above: argc = 3; argv[] = ["echo", "hello,", "world", 0] echo is a Unix command which echoes its command line arguments on a single line, separated by blanks echo hello, world prints: hello, world #include // echo main(int argc, char *argv[]) { int i; for (i=1; i<argc; i++) printf("%s%s", argv[i], (i < argc-1) ? " " : ""); printf("\n"); return 0; } // grep: print lines matching patterns in arg[1] #include #define MAXLINE 1000 main(int argc, char *argv[1]) { char line[MAXLINE]; int found = 0; if (argc != 2) printf("Usage: find pattern\n"); else while(geline(line, MAXLINE) > 0) if (strstr(line, argv[1]) != NULL) { printf("%s", line); found++; } return found; } NULL is #defined as 0 in and is used when checking for null ptrs strstr(s,t) returns a ptr to the first occ. of s in t or NULL if there is none
11
11 Ptrs to functions qsort(): To sort an array of numbers, qsort moves the part. elmt to v[0] then goes through all the numbers, moving *smaller numbers* to the left side and then moving the part. elmnt. to their immediate right … To sort an array of strings, we just had to change that to *smaller strings* and change the type of the first par. (of qsort() and also of swap()) // qsort: sort v[left] … v[r] in incr. order void qsort(int v[], int left, int right) { //void qsort(char* v[], int left, int right) { int i, last; if (left >= right) return; // less than 2 elmts swap(v, left, (left+right)/2); //move part. last = left; //elmt to v[0] for (i=left+1; i <= right; i++)// partition if (v[i] < v[left]) swap(v, ++last, i); // if (strcmp(v[i],v[left]) < 0) swap(…) swap(v, left, last); // restore partition elmt qsort(v, left, last-1); qsort(v, last+1, right); } void swap(int v[], int i, int j) { //void swap(char* v[], int i, int j) { int temp; //char* temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } Idea: have qsort() have an additional parameter which is the *comparison operation* to be performed to determine which of two elements of the array is smaller … using pointers to functions
12
12 Ptrs to functions // qsort: sort v[left] … v[r] in "incr. order" //void qsort(char* v[], int left, int right) { void qsort(void *v[], int left, int right, int (*comp)(void *, void *) ) { … for (i=left+1; i <= right; i++)// partition // if (v[i] < v[left]) swap(v, ++last, i); if ((*comp)(v[i],v[left]) < 0) swap(…) swap(v, left, last); // restore partition elmt … //void swap(char *v[], int i, int j) { void swap(void *v[], int i, int j) { //char* temp; void* temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } void *x: means x is a pointer to ANY type of value void *x[]: means x is an array of pointers each of which points to any type of value int (*f)(int, int): means f is a *pointer to a function* which expects two int parameters and returns an int Important: int *f(int, int): VERY different! f is a fn. that returns a ptr to an int int (*f)(void *, void *): means f is a ptr to a function that expects two ptrs to any types of values and returns int
13
13 Structures struct point makepoint(int x, int y) { struct point temp; temp.x = x; // temp.x,x unrelated temp.y = y; return temp; } struct rect screen; struct point middle; screen.pt1 = makepoint(0, 0); screen.pt2 = makepoint(XMAX,YMAX); middle = makepoint( (screen.pt1.x+…)/2,(screen.pt1.y+…)/2)); // parameters are passed by value; e.g.: struct point addpoint(struct point p1, …p2){ p1.x += p2.x; p1.y += p2.y; return p1; } The caller's ap1, ap2 unaffected by this No classes in C, use struct: struct point { int x; int y; } That defines a new type: struct point pt; // pt has 2 components: p.x, p.y everything is public pt.x = 100; pt.y = 200; struct rect { struct point pt1;// not "point pt1;" struct point pt2; } struct rect screen; // screen.pt1.x means the x // component of pt1 of screen struct point origin, *pp; … pp = &origin; printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);//or pp->x, pp → y Pointers to (large) structs are useful and help avoid making copies
14
14 Recursive structs struct tnode { char *word; int count; struct tnode *left; //MUST be a pointer struct tnode *right; } Read sections 6.3, 6.4 6.3 uses arrays of structs 6.4 shows use of ptrs to arrays of structs Same problem is solved: counting occurrences of C keywords in a file Solution: Use a binary tree where each node consists of: a word that has been seen count of how many times (so far) *and* pointers to two children nodes (either/both may be NULL) Problem: count the occurrences of all the words in a document Key point: list of words is not known in advance … so linear search will be too slow Solution (contd.): The word WL in the left child node L of a given node N is less than the word at N; the word WR at R is greater than the word at N. When a new word W comes in, compare it with word at root; if it matches, increment count at that node; if not, if W is less, and there is no left child, create it …; else handle left child node recursively … //mutually rec. structs: struct t { … struct s *p; … } struct s { … struct t *q; … }
15
15 Recursive structs (contd) #include #define MX 100 struct tnode *addtree(struct tnode *, char *); void treeprint(struct tnode *); int getword(char *, int); main() { struct tnode *root; char word[MX]; root = NULL; // is 0 – null ptr while (getword(word, MX)) != EOF) if (isalpha(word[0])) root = addtree(root, word); treeprint(root); return 0; } struct tnode *talloc(void); char *strdup(char *); struct tnode *addtree(struct tnode *p, char *w) { int cond; if (p==NULL) { //a new word p = talloc(); p → word = strdup(w); p → count =1; p → left = p → right = NULL; } else if (cond=strcmp(w, p→word)) == 0) p → count++; else if (cond < 0) p → left = addtree(p→left, w); else p → right = addtree(p→right, w); return p; }
16
16 Recursive structs (contd) void treeprint(struct tnode *p) { if (p != NULL) { treeprint(p→left); printf("%4d %s\n", p→count, p→word); treeprint(p→right); } } char *strdup(char *s) { // make a duplicate char *p; p = (char *) malloc(strlen(s)+1); if (p !=NULL) strcpy(p, s); return p; } We have to use an important function called malloc() for dynamic memory allocation: #include struct tnode *talloc(void) { return(struct tnode *) malloc(sizeof(struct tnode)); } Read Section 6.6 for a more involved ex.
17
Pre-processor C programs may include a number of pre- proc. commands (start with "#"): #include or #include "filename" (if any included file is changed, must recompile) #define name replacement text This is textual replacement; so be careful! #define square(x) x*x square(x+1) will become x+1*x+1 #undef getchar // ensures getchar is not a macro int getchar(void) { … } CSE 3430; Part 5 17
18
Pre-processor (contd) #if : allows for conditional commands to the pre-processor: #if SYSTEM==SYSV #define HDR "sysv.h" #elif SYSTEM==BSD #define HDR "bsd.h" #else #define HDR "default.h" #endif #include HDR #ifdef and #ifndef : specialized forms for testing if a name is defined or not CSE 3430; Part 5 18
19
Debugging C code Use gdb; see "guide" on course homepage 19 cc -g sf.c// -g is for debug; -o: for exec. filename gdb a.out// gdb will start on a.out or (exec. filename) "r" or "r < z" // run or run with z as cmd. ln. args "l" or "l 52" or "l X.c:52" or "l fn1"// list "b 52" "b fn1"// set breakpoint b 3 (Z > 52)// makes bkpnt. 3 conditional disable 3// disables bkpnt 3 "p X" or "disp X"// latter displays *every* time after stopping undisplay X "s" or "n"//*important*: one step/function at a time bt//"backtrace": useful on error; tells which fn called which set variable X=12//changes value of X; use with care define//lets you give a name to complex commands CSE 3430; Part 5
20
Input/Output Library implements simple model of text i/o a text stream is a seq. of lines, each ending with \n (if system doesn't work that way, the library makes it look like it does) Three standard streams: stdin, stdout, stderr Can be redirected using " " prog outfile Can use piping to send output of one prog. to another: prog | anotherprog 20
21
UNIX system interface Ch. 7 &, *especially*, 8 are *important*; read them carefully! OS provides its services through a set of functions ("system calls") that may be called by user programs Files: All i/o is done by reading/writing files; all devices (even keyboards, screens, …) are treated as files in the file system To use a file, you have to open it (or create it) in the appropriate mode system will check if you have the right to do so and, if so, returns a file-descriptor (~ file pointer but an int) When the UNIX command interpreter ("shell") runs a program, three files are open, with file descriptors 0, 1, 2 If you type, "prog outfile", the *shell* assigns 0 and 1 to infile and outfile CSE 3430; Part 5 21
22
UNIX system interface (contd) // input/output use the read and write system calls int read(int fd, char *buf, int n); //n is no. of bytes to be read; maybe large //returns number actually read; 0 means EOF; -1 means error int write(int fd, char *buf, int n); //error if returned value != n int lseek(int fd, long offset, int origin); //moves "cursor" by offset; //origin: 0/1/2: from the start/current/end //lseek(fd, 0L, 0); // will "rewind" CSE 3430; Part 5 22
23
UNIX system interface (contd) CSE 3430; Part 5 23 #include int getchar(void) { // buffered version using raw read() static char buf[1000]; //better: use BUFSIZE if available static char *bufp = buf; static int n = 0; if (n==0) { n=read(0,buf,1000); bufp = buf; } return (--n >= 0) ? (unsigned char) *bufp++ : EOF; // *bufp++ is char bufp pointed to before being // incremented; casting eliminates sign extension problems } //using lseek(), we can treat a file as a large (but slooow!) array int get(int fd, long pos, char *buf, int n) { //read n bytes from "position" ps if (lseek(fd,pos,0) >= 0) //move to pos return read(fd, buf, n); else return -1; } //But higher-level i/o functions are very imp. as well; see ch. 7 //especially printf, scanf, sprintf, and sscanf
24
Open, Creat, Close, Unlink CSE 3430; Part 5 24 #include main(int argc, char *argv[]) { //like cp int f1, f2, n; int RD=O_RDONLY; int P=0666; char buf[1000]; if (argc != 3) printf("Usage: cp from to"); if ((f1=open(argv[1],RD,0))==-1) printf("cp: can't open %s", argv[1]); if ((f2=creat(argv[2],P))==-1) printf("cp: can't create %s", argv[2]); while ((n=read(f1,buf,1000))>0) if (write(f2,buf,n) != n) printf("write error: %s", argv[2]); return 0; } In addition to read, write, three other key file manipulation functions on UNIX: int open(char *name, int flags, int perms): //opens file with perms //returns fd or -1 if error int creat(char *name, int perms): //creates file and returns //fd (or -1 if it fails) //if file already exists, its //contents are erased! void close(int fd): //useful since can't have //more than a certain no. //of open files unlink(char *name): //*removes* the file Read ch. 8; not easy to read but worthwhile!
25
UNIX Directories and files … CSE 3430; Part 5 25 Browse through some of the the files in /usr/include You will get a good idea of all the functions that are available to C prgrmers A directory is file that contains, for each file in the directory, its name and a number, which is an index into the inode list: typedef struct { int ino; char name[20]; } Dirent; typedef struct { int fd;//file descriptor for dir Dirent d; } DIR; The inode of a file contains all the info about the file (except its name) //print the contents of curr. dir. #include int main (void) { DIR *dp; struct dirent *ep; dp = opendir ("./"); if (dp != NULL) { while (ep = readdir (dp)) puts (ep->name); closedir (dp);} else return -1; return 0;}
26
UNIX Directories, files (contd) CSE 3430; Part 5 26 Write a program that counts the total number of characters in the names of each of the files in the current directory, not including entries that are themselves directories struct stat {//info in inode dev_tst_dev; //device of inode ino_st_ino; //inode no. intst_mode;//mode bits intst_nl; //# of links to file intst_uid;//owner user id int st_gid;//owner's gp. id intst_size;//size in bytes timest_at;//time last accessed timest_mt;//time last modified timest_at;//time created //mode bits tell if it is a reg. file, //directory, etc.}; int stat(char *, struct stat *); //returns inode information //st_mode contains a set of bits //whose values tell us the type #define S_IFMT 0160000 #define S_IFDIR 0040000 #define S_IFCHR 0020000 #define S_IFBLK 0060000 #define S_IFREG 0100000 *Bit manipulation*, using &, |, and ^ is common in pgms at this level; e.g.: void fsize(char *name) { … if ((stbuf.st_mode & S_IFMT) == S_IFDIR) … / is a dir. …}
27
Other important functions CSE 3430; Part 5 27 //malloc returns ptr to n bytes of uninit. storage char *strdup(char *s) { // make a duplicate char *p; p = (char *) malloc(strlen(s)+1); if (p !=NULL) strcpy(p, s); return p; } //calloc returns ptr to space for an array int *ip; ip = (int *) calloc(n, sizeof(int)); //free returns space previously allocated but careful! for (p=head; p != NULL; p = p→next) free(p); // serious error! // copy p→next into q, then free p //Read chapter 7: lot of details but not complex
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.