CSC 357 Lecture Notes Week 3
Leftovers from Week 2 Notes; Additional C Language and Library Features



  1. C Input and Output (K&R Chapter 7).
    1. Strictly speaking, I/O is not part of the C language.
    2. Rather, it is part of the standard library.
    3. You have already seen and used important I/O functions defined in stdio.h.
    4. We'll cover things in further detail here, and the weeks to come.

  2. Standard input and output (K&R Section 7.1).
    1. The names of the file streams are stdin, stdout.
    2. The simplest way to read from and write to stdin and stdout are the char-at-a-time functions getchar and putchar.
    3. printf also goes to stdout.
    4. I/O to and from the stdio streams can be redirected and piped with the shell operators '<', '>', and '|', which are introduced in K&R and the 357 UNIX Basics handout; they are covered further in the tcsh man page.

  3. Formatted output -- printf and sprintf (K&R Section 7.2).
    1. You've used this plenty already.
    2. Do read the printf man page.
    3. Page 154 of K&R has a handy table of % formatting codes.
    4. The sprintf function let's you do in-memory "printing".
      1. It does the same thing as printf, but to a string buffer, which must be large enough to hold the produced output.
      2. The first argument to sprintf is the char* buffer; the rest of the arguments are exactly the same as printf.

  4. Variable-length argument lists (K&R Section 7.3).
    1. printf has a variable number of args after the first.
    2. You can define your own functions using macros provided in the system library <stdarg.h>, the man page for which you should read.
    3. We'll cover the definition of functions with variable-length argument lists in an upcoming lab and assignment.

  5. Formatted input -- scanf (K&R Section 7.4).
    1. The scanf function is the input analog of printf.
    2. The first scanf argument is a formatting string in the same style as print.
    3. For scanf, the '%' codes in the formatting string govern how inputs are interpreted and converted.
    4. The input variables are the scanf arguments following the formatting string.
    5. We'll not use scanf much in 357, but will cover it a bit in an upcoming lab.

  6. File access (K&R Section 7.5).
    1. The functions discussed thus far work with stdin and stdout.
    2. To read from a stored file, you need first to open it with the function fopen, the signature for which is
      FILE* fopen(char* name, char* mode);
      
      1. The first argument is the name of the file to open.
      2. The second argument is mode of the file, as specified at the shell level; these file modes are covered in the UNIX Basics handout; and the fopen man page.
    3. The type FILE is a structure declared in <stdio.h>, the details of which programmers need not generally be aware.
    4. Character-level reading from and writing to files is done with the functions getc and putc, which both take a FILE* a their only argument.
    5. The functions operate just as getchar and putchar do on the standard i/o streams, and in fact the following macro definitions show the equivalence of the functions:
      #define getchar() getc(stdin)
      #define putchar() putc(stdout)
      
    6. There are file versions of scanf and printf, with the following signatures:
      int fscanf(FILE* fp, char* format, ...)
      int fprintf(FILE* fp, char* format, ...)
      
      See the man pages for each for further discussion, including what the return values are used for.
    7. The fclose function closes a file opened with fopen; since most operating systems have a limit on the number of files that can be open at the same time, it is a good idea to use fclose whenever a file is no longer needed.

  7. Error handling -- stderr and exit(K&R Section 7.6).
    1. Output from printf goes to the stdout stream.
    2. C provides a second output called stderr, to which error messages can be printed.
      1. Output can be sent to stderr using fprintf, as in
        fprintf(stderr, "%s: No such file or director", filename);
        
      2. When stdio is redirected to a file with '>', the stderr stream still appears on the terminal.
      3. To redirect both stdio and stderr, use the '>&' redirection operator.
    3. A C program signals an error in two ways -- via the stderr stream and using the exit system function.
      1. Calling exit terminates program execution.
      2. The integer argument value of exit is the value returned by the entire program.
      3. Conventionally, a value of 0 means the program exited normally.
      4. Non-zero exit values can be used to signal specific error conditions.
      5. UNIX system calls usually return a value of -1 to signal an error, and set the external variable errno to a value that can be read by the perror function.

  8. Line input and output (K&R Section 7.7).
    1. The fgets reads a line of input from a file stream; its signature is
      char* fgets(char* line, int maxline, FILE* fp)
      
      If successful, it returns the filled line, a null pointer otherwise.
    2. The fputs function is the output analog
      int fputs(char* line, FILE* fp)
      
      If successful, it returns the number of chars output, EOF otherwise.

  9. Miscellaneous functions (K&R Section 7.8).
    1. This section of K&R provides a brief overview of system functions we have been using in the assignments.
    2. The man pages and Stevens book have more detailed information.

  10. Makefiles.
    1. See the Gnu manual page, cited in this week's lab writeup.
    2. Purpose of makefiles is to hold commands so they can be conveniently executed by a (short) name.
      1. Frequently, Makefiles are used for compilation commands
      2. However, any and all UNIX commands can be used in Makefiles.
      3. So in addition to compilation, Makefiles can be used to run testing programs, print listings, and perform other program construction tasks.
    3. Make also performs "smart recompilation" in that the compiler is only re- executed when source files change since the most recent compilation.
    4. During lecture and/or lab, we'll dissect Makefiles for the linked-list program -- the original "full-blown" version supplied with the linked-list code examples, and the simplified versions in the Lab 3 writeup.

  11. The static storage class (K&R Section 4.6).
    1. Variables in a C program can be declared static, as in
      static int i;
      
    2. Within a C source file, external variables declared static are not visible in other C source files; i.e., the scope of the static variables is local to the C file in which they are declared.
    3. The static storage class can also be used for local function variables, where it has the effect of extending the lifetime of the variable to that of the entire program.
    4. We'll discuss the use of static function variables in an upcoming lecture.

  12. Memory layout in a C program.
    1. The memory used by a C program is organized conceptually into three storage areas:
      1. The static pool, containing variables declared outside of functions, and local function variables declared static.
      2. The stack, containing function parameters and local variables; stack data are stored in activation records for each function call.
      3. The heap, containing storage allocated dynamically by malloc and friends.
    2. The lifetime of storage in the three pools is the following:
      1. The lifetime of static-pool variables is the lifetime of the entire program.
      2. The lifetime of function parameters and non-static local variables is the activation lifetime of the function in which they are declared.
      3. The lifetime of allocated heap storage is until it is freeed, or until the program ends, which ever occurs first.
    3. Consider the following example.

      #include <strings.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      char s[20];
      
      char* f(char* s1, char* s2, int* ip) {
          char* s3;
      
          s3 = strcat(s1, s2);
          strcpy(s, s3);
          *ip = strlen(s3);
          return s3;
      }
      
      void main() {
          char s1[20] = "abcdef";
          char* s2 = strcpy((char*) malloc(strlen("ghijklmn")), "ghijklmn");
          char* s3;
          int i;
      
          s3 = f(s1, s2, &i);
          free(s2);
          printf("s=%s, s3=%s, length of s=%d, length of s3=%d0, s, s3, strlen(s), i);
          printf("sizeof(s)=%d, sizeof(s3)=%d0, sizeof(s), sizeof(s3));
      }
      
    4. During lecture, we'll draw some pictures of the three memory pools as this program executes.

  13. Program modularization and information hiding in C.
    1. C programs can be nicely modularized using pairs of .h and .C files.
      1. The .h file contains type declarations, function declarations (i.e., signature), global constants, and global variables.
      2. The .C file contains the implementation of the functions.
    2. The static declaration provides information hiding.
      1. Global variables declared static are visible only to the functions declared in the module, and hence act like private variables in object-oriented languages like Java and C++.
      2. Functions declared static are similarly limited in visibility.

  14. doxygen
    1. doxygen is a documentation-generation tool for C and C++ programs
    2. It operates very much like javadoc does for Java.
    3. As an example during lecture, we'll look at the C source code and generated documentation for the person-record program, which is the subject of this week's lab.



index | lectures | labs | programs | handouts | solutions | examples | documentation | bin