Write a C program that will display the contents of a file to stdout
in a manner similar to
the od command-line tool (see: man od).
Put your source code in the file lab1.c.
- Login to a Linux machine.
- We will be working from the command line a lot in this course,
so figure out how to create a terminal window.
- 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.
If it is not available from the applications menu, it may be
invoked from the command line.
(Type: ghex)
- 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.
If it is not available from the applications menu, it may be
invoked from the command-line.
(Type: gedit)
-
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.
- 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.
- 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.
- 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.)
- Construct a loop that will loop until EOF
is returned by getc.
Include at the bottom of the loop another call to getc.
- 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.
- Save what you have edited so far and exit the editor.
- 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
- Add code to print 16 bytes of the file per line:
- Add an if statement to the top of the loop to test if the
counter variable modulo 16 is equal to zero.
(The C operator % computes modulo.)
If so, print the current counter variable in the following way:
printf("\n%08d", cnt);
Note the %08d format for printing an integer value
in decimal with a minimum width of 8 characters using 0 to fill on
the left.
- Add to the body of the loop another call to printf,
prior to the call to getc, to print in the following
way the last character read:
printf(" %02x", c);
Note the %02x format for printing an integer value
in hexadecimal with a minimum width of 2 characters using 0 to fill on
the left.
- Change the final print done after the loop is exited to use
a format string of "\n%08d\n" rather than
"%d\n".
- 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.
- Tinker with the code to remove the blank line that is initially
printed.
- 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.
- 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.c > 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;
}
-
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.
-
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