CS520
Spring 2017
Laboratory 1
Friday January 27
The lab must be submitted prior to noon on Sunday January 29.


Write a C program that will display the contents of a file to stdout in a manner similar to the od command-line tool. (To learn more about od, in a command-line window type man od).) Put your source code in the file lab1.c.

Follow these steps to complete the lab:

  1. Login to a Linux machine.

  2. We will be working from the command line a lot in this course, so figure out how to create a terminal window. Typically you select Terminal Emulator from the Applications menu.

  3. Play around with od. Use it with the -tx1 command-line flag to display the contents of a file in hexadecimal. First, look at an ASCII file, such as /etc/printcap. (Type: od -tx1 /etc/printcap) Next, look at a binary file, such as /bin/ls. (Type: od -tx1 /bin/ls)

    Be sure you understand the output. od displays, by default, sixteen bytes per line, with each line beginning with the offset in the file of the first character on the line. One tricky thing is that the offset is displayed in octal.

    You may also want to play around with ghex, which is a graphical application for viewing and editing binary files. It is typically available from the Development tab of the Applications menu. It may also be invoked from the command line (type: ghex).

  4. Use a text editor to create and edit a file called lab1.c. I recommend learning to use a command-line editor, such as vi or emacs, but today you may prefer to use a graphical editor, such as gedit. It is typically available from the Accessories tab of the Applications menu. It also may be invoked from the command-line (type: gedit).

  5. Include stdio.h, include stdlib.h, and define the main function with this prototype:
    int main(int argc, char *argv[])
    
    Have the function return 0.

    Note that returning 0 from the main function indicates success to the invoking shell program (command-line processor). A non-zero return value indicates failure.

  6. Add an if statement to check if argc is equal to two. If not, print an error message and exit the program using the following code:
    printf("Usage: lab1 filename\n");
    exit(-1);
    
    printf prints strings to stdout. The integer value passed to exit is the status returned by the program to the invoking shell.

  7. Use fopen to open for reading the file whose name is given as the second command-line argument: fopen(argv[1], "r"). (Note that argv[0] refers to the name of the program being executed.) Save the return value into a variable of type FILE *. Check the return value to be sure the file was opened successfully. The value will be NULL if the file failed to open. In this case print an error message and exit:
    printf("cannot open %s\n", argv[1]);
    exit(-1);
    
    Note the use of the %s for formating a string value within the string to be printed by printf.

  8. Perform a priming read of the opened file, using getc, which takes as its only argument the value returned by fopen. Capture the return value of getc into a variable of int type. getc reads one byte from the file, but places it in an int container with the upper bytes being zeroes. This is so it can return a special int value that indicates EOF has been reached. This special value can be referred to as EOF. (Note that there is no EOF character in a file. Unix systems track the length of the file in order to know when EOF has been reached.)

  9. Construct a loop that will loop until EOF is returned by getc. Include at the bottom of the loop another call to getc.

  10. Prior to the loop, initialize a counter variable to zero. In the body of the loop (prior to the call to getc) increment the counter. After the loop terminates, print the value of the counter variable in the following way:
    printf("%d\n", counterVariable);
    
    Note the use of the %d for formating an integer value in decimal within the string to be printed by printf.

  11. Save what you have edited so far and exit the editor.

  12. Compile and run the program:
    % gcc -Wall lab1.c -o lab1
    % ./lab1 /etc/printcap
    
    Check you answer by using the ls command:
    % ls -l /etc/printcap
    

  13. Add code to print 16 bytes of the file per line:
  14. Re-compile and re-test your program. Compare the answers to what is produced by od -tx1. They should be the same except the offset your program prints at the beginning of the line will be in decimal, rather than octal.

  15. Tinker with the code to remove the blank line that is initially printed.

  16. Be sure you understand what your program (and od -tx1) are doing. They are showing you the contents of a file, one byte at a time. Realize that a byte is just an 8-bit integer value, which is being displayed in hexadecimal. If you process an ASCII text file, your program will be displaying the ASCII codes for the characters being represented.

  17. Create other test files, by writing a separate program that uses putc to write bytes to a file. In this case use fopen to open a file for writing. Also note that open files can be closed using fclose. Use the man tool to learn about the details of putc, fopen and fclose:
    % man putc
    % man fopen
    % man fclose
    
    Of course, since these are standard C library functions, you might also learn more about these and other C library functions by googling their names or consulting a C reference.

    putchar is like putc except it always writes to stdout. (Similarly, getchar is like getc except it always reads from stdin.) You could create test files by writing a program that uses putchar and then re-direct the stdout of your program into a file:

    % gcc createTest.c -o createTest
    % ./createTest > testFile
    
    (stdin can also be re-directed by using a less-than rather than greater-than, i.e.:
    % ./programName < inputFile
    

    For instance, here is a program to create a short test file containing three bytes:

    #include <stdio.h>
    int main(void)
    {
      putchar(0x01);
      putchar(0xEF);
      putchar(0xA1);
    
      return 0;
    }
    

  18. Use gdb to step through your program, examine your variables, etc. You probably won't need it to debug this lab, but you will need it later so learn its basic features now, if you don't know/remember them. ddd provides a graphical interface to gdb. (Typically ddd is available as Data Display Debugger under the Development tab of the Applications menu.)

  19. To turn in this laboratory, type:
    % ~cs520/bin/submit lab1 lab1.c
    

    Submissions can be checked by typing:

    % ~cs520/bin/scheck lab1
    

60 points will be awarded for reading a file, detecting EOF, and displaying the length of the file. 40 additional points will be awarded for displaying the full od-like output.

Remember that there are no late submissions of labs. Submit what you have prior to noon on Sunday January 29.


Last modified on January 26, 2017.

Comments and questions should be directed to pjh@cs.unh.edu