|
Meeting Signup |
Projects /
P0CS 537 Spring 2008 Section 1: Programming Homework 0Due: Tuesday, January 27th at 9 pm You are to do this project BY YOURSELF This project must be implemented in C (and not C++ or anything else) Notes:Monday, January 26Hint 2: you can assume that the input is a well-formed text file, meaning that it contains no null characters. Thursday, January 22Hint 1: here is sample code from this web site showing how to allocate a two dimensional array: int **array1 = (int **)malloc(nrows * sizeof(int *)); for(i = 0; i < nrows; i++) array1[i] = (int *)malloc(ncolumns * sizeof(int)); array1[1][2] = 0; Hint 2 (student generated): it may be easier to test your code for correctness by reducing the maximum length of the file and length of the line. Once that works, you can experiment on larger files. PurposeThe purpose of this assignment is to get familiar with the C programming language, the gcc compiler, and the gdb debugger. Part 0: a pictureWe want to get to know you better, and what better way than to be able to associate a name with a face? You need to turn in a digital picture of yourself so I can learn who you are. Put this in your handin directory (a jpg or a gif is fine), in the form Firstname.Lastname.jpg (or whatever). If you don't turn in a picture, your project will not be graded! Part 1: Writing C codeYou will write a program to read in a text file and print the lines in reverse order (last line first, first line last) and also print out each line in reverse order (last non-newline character first, first character last). Specification: Program input: read a file specified on the command line: reverse-lines filename.txt Program output: every line of the file, in reverse order. Note that the lines of the file may be very short (blank) or very long (up to hundreds of characters). This input: <!--#include file="base-head.html" --> <title>CS 537: Operating Systems</title> <!--#include file="base-top.html" --> <h2>Overview</h2> <p> Welcome to your first the Wisconsin Operating Systems course. This course will describe a number of topicsincluding basic operating system structure, process and thread synchronization and concurrency, file systems and storage servers, memory management techniques, process scheduling and resource management, system security, and a few other "hot" topics. should produce this output: .scipot "toh" rehto wef a dna ,ytiruces metsys ,tnemeganam ecruoser dna gniludehcs ssecorp ,seuqinhcet tnemeganam yromem ,srevres egarots dna smetsys elif ,ycnerrucnoc dna noitazinorhcnys daerht dna ssecorp ,erutcurts metsys gnitarepo cisab gnidulcniscipot fo rebmun a ebircsed lliw esruoc sihT .esruoc smetsyS gnitarepO nisnocsiW eht tsrif ruoy ot emocleW >p< >2h/<weivrevO>2h< >-- "lmth.pot-esab"=elif edulcni#--!< >eltit/<smetsyS gnitarepO :735 SC>eltit< >-- "lmth.daeh-esab"=elif edulcni#--!< AssumptionsString length: You may assume no line in the input file is longer than 512 bytes. If you encounter a line that is too long, you should print error message LINE_TOO_LONG (as detailed below) and skip the rest of this line. Let's say the max size of an input line is 8 characters (and not 512). Which of these lines should be in the final output? abcdef abcdefg abcdefgh The first seemingly has 6 characters (abcdef), the second has 7, and the third 8, and thus you might naively think all should be accepted. However, you are forgetting the newline character (\n) which is at the end of each input line. Thus, the first two should be accepted (as they have 7 and 8 characters including the newline). For the third line, you should only accept 'abcdefg' and put a \n, and skip the rest of the line, and don't forget to print the LINE_TOO_LONG message. File length: You may assume the input file has 1024 valid lines (not too long) of input or fewer. If you encounter more lines, print the FILE_TOO_LONG error message once (as detailed below) and reverse whatever input you currently have read in. Error MessagesAll error messages encountered while reading the input file should be of this format: Error in line XXX: specific error message where the specific error messages are: FILE_TOO_LONG: You should print the following message: File too long Error: Cannot open file FILE where FILE is what the user passed in. There are some other possible errors too. For example, if the user doesn't properly specify the input file on the command line (by say, not giving one, or by giving too many files), you should print: usage: reverse <file> and then exit. Important: On any error code, you should print the error to the screen using fprintf() , and send the error message to stderr (standard error) and not stdout (standard output). This is accomplished in your C code as follows: fprintf(stderr, “usage: ... ”); Implementation tips: To do this, use the C standard I/O "f" functions: fgetc, fputc fgets, fgets fscanf, fprintf fopen, fclose Documentation for these functions are available through the Linux man pages: emperor01(1)% man fgets GETS(3) BSD Library Functions Manual FGETS(3) NAME fgets, gets -- get a line from a stream LIBRARY Standard C Library (libc, -lc) SYNOPSIS #include <stdio.h>
char *
fgets(char *restrict s, int n, FILE *restrict stream);
char *
gets(char *s);
To invoke the compiler, run the command line: emperor01(1) gcc -g -o programname filename.c This will compile the file "filename.c" and produce the output program "filename" that you can then run with the command "./filename" (the "./" is to tell Linux in which directory to find the program. The "-g" flag indicates that the compiler should produce extra data to enable source-level debugging, and the "-o" options specifies to put the program in a specific file as compared to the standard name "a.out". Other TipsStart small, and get things working incrementally. For example, first get a program that simply reads in the input file, one line at a time, and prints out what it reads in. Then, slowly add features and test them as you go. Testing is critical. One great programmer I once knew said you have to write 5-10 lines of test code for every line of code you produce; testing your code to make sure it works is crucial. Write tests to see if your code handles all the cases you think it should. Be as comprehensive as you can be. Of course, when grading your projects, we will be. Thus, it is better if you find your bugs first, before we do. Keep old versions around. Keep copies of older versions of your program around, as you may introduce bugs and not be able to easily undo them. A simple way to do this is to keep copies around, by explicitly making copies of the file at various points during development. For example, let's say you get a simple version of myreverse.c working (say, that just reads in the file); type cp myreverse.c myreverse.v1.c to make a copy into the file myreverse.v1.c . More sophisticated developers use version control systems like CVS , but we'll not get into that here (yet). Keep your source code in a private directory. An easy way to do this is to log into your account and first change directories into private/ and then make a directory therein (say p1 , by typing mkdir p1 after you've typed cd private/ to change into the private directory). However, you can always check who can read the contents of your AFS directory by using the fs command. For example, by typing in fs listacl . you will see who can access files in your current directory. If you see that system:anyuser can read (r) files, your directory contents are readable by anybody. To fix this, you would type fs setacl . system:anyuser “” in the directory you wish to make private. The dot “.” referred to in both of these examples is just shorthand for the current working directory. Part 2: Debugging C codeThe gdb debugger allows you to stop your program at any point and investigate program variables. Specification:Start your program under the debugger. Put a breakpoint on your main loop reading a line from the file. Single step through input of a single line. Print out the values of at least two different variables. Submit a transcript of your debugging session. Implementation tips:You start gdb by invoking it with the program name: emperor01(5)% gdb programname GNU gdb Red Hat Linux (6.5-37.el5_2.2rh) Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) Start running your program with the "run" command any input or output redirection: (gdb) run < filename.c You can set breakpoints on a function with the "break" command and pass it either a function name or a file and line number: (gdb) break main Breakpoint 1 at 0x8048419: file filename.c, line 8. (gdb) break filename.c:11 Breakpoint 3 at 0x804841e: file filename.c, line 11. (gdb) You can print variables with the "print" command: (gdb) print stdin $3 = (struct _IO_FILE *) 0x2ae420 (gdb) You can list code with the "list" command, which takes a function name or a filename:linenumber (like break): (gdb) list main
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(int argc, char * argv[])
5 {
6 char buffer[200];
7 char * tmp;
8 while (!feof(stdin)) {
9 int len;
10 int i;
(gdb)
After execution stops at a breakpoint, you can continue exection with the "cont" command: (gdb) run < filename.c
Starting program: /afs/cs.wisc.edu/u/s/w/swift/tmp/programname <
filename.c
Breakpoint 1, main () at filename.c:8
8 while (!feof(stdin)) {
(gdb) cont
Continuing.
One execution stops, you can step forward one source code line at a time with the "next" command (abbreviated "n"), which jumps over function calls, or the "step" command (abbreviated "s"), which goes into the function and stops: Breakpoint 1, main () at filename.c:12
12 while (!feof(stdin)) {
(gdb) next
15 tmp = fgets(buffer, 200, stdin);
(gdb) next
16 if (tmp == 0){
(gdb) next
19 len = strlen(tmp);
(gdb) next
20 for (i = len-2; i >= 0; i--) {
(gdb) next
21 printf("%c",myfunction(tmp[i]));
(gdb) step
myfunction (c=62 '>') at filename.c:5
5 return((int)c);
(gdb)
You can quit gdb with the "quit" command. What to turn in:
What we will look for:
|