Spring 2002 COMP 122 Peter Smith

Handout #8

C – Part 2

In this handout we look at some features of C that you will probably not need this semester but will be handy in future classes.

Redirection of input and output

When running programs in a Unix environment, a simple way to read data from a file into a program and to save results and/or error messages to a file without making any changes to the program source code is to use the Unix shell redirection.

A C program has three built-in file streams: stdin, stderr and stdout. When you use scanf you are reading from stdin. When you use printf you are writing to stdout.

The following table shows how you can redirect the three streams when calling a.out.

Command

/

Stdin

/

Stdout

/

Stderr

a.out / Keyboard / Screen / Screen
a.out < Datafile / Datafile / Screen / Screen
a.out > Results / Keyboard / Results / Screen
a.out < Datafile > Results / Datafile / Results / Screen
a.out & Allout / Keyboard / Allout / Allout
a.out < Datafile & Allout / Datafile / Allout / Allout
(a.out > Results) & Errors / Keyboard / Results / Errors
(a.out < Datafile > Results) & Errors / Datafile / Results / Errors

Later we look at attaching files to programs in general.

Command line arguments

In general, the main program function can have the following heading

main(int argc, char *argv[])

When the program runs, the operating system puts into argc (argument count) the number of tokens on the command line. This count includes the program name itself. Pointers to the texts of the tokens is put into the elements of argv (argument vector). Here is a simple program; it just echoes the components of the command line back to the standard output.

Example 13

#include <stdio.h>

int main (int argc, char* argv[])

{

int i;

printf("argc is: %d\n", argc);

for (i=0; i<argc; i++) printf("argv [%d] is %s\n",i,argv[i]);

}

Here is the compilation and a run of the program (gcc is the Gnu C compiler).

hp9k2 22: gcc ctesta.c

hp9k2 23: a.out one two three

argc is: 4

argv [0] is a.out

argv [1] is one

argv [2] is two

argv [3] is three

More pre-processor options

We can define symbols as in

#define MAXMEM 4096

#define PI 3.14159

to be used in various ways. For example we could declare int memory[MAXMEM]. Also we can define symbols to control debugging as in the following example.

Example 14

#define DEBUG 1

main()

{

int a[] = {2, 4, 3, -1, 7 };

int i,sum=0;

for (i=0; i<5; i++)

{

sum += a[i];

#ifdef DEBUG

printf ("sum is now %d\n",sum);

#endif

}

printf("sum is %d\n", sum);

}

The line between #ifdef and #endif is only included in the output from the preprocessor (and hence input to the compiler) if the symbol DEBUG has a non-zero value. There is also #ifndef.

hp9k2 22: gcc ctestb.c

hp9k2 23: a.out

sum is now 2

sum is now 6

sum is now 9

sum is now 8

sum is now 15

sum is 15

To remove the debugging information from the input to the compiler we need only change the value of the symbol to 0 (or to omit its definition altogether) thus

#define DEBUG 0

main()

{

int a[] = {2, 4, 3, -1, 7 };

int i,sum=0;

for (i=0; i<5; i++)

{

sum += a[i];

#ifdef DEBUG

printf ("sum is now %d\n",sum);

#endif

}

printf("sum is %d\n", sum);

}

Now when the program is compiled the debug statements are omitted

hp9k2 26: gcc ctestb.c

hp9k2 27: a.out

sum is 15

Macros

The preprocessor recognizes macro definitions. Consider the following program

Example 15

#include <stdio.h>

#define SQ(x) ((x) * (x))

main()

{

int i=4, j=9;

printf("%d %d %d\n",SQ(i),SQ(j),SQ(i+j));

}

When run, it outputs

16 81 169

Text files

We can attach text files to programs and read them in a simple way as in the following example

Example 16

#include <stdio.h>

#include <string.h>

main()

{

FILE *ifp, *ofp;

char temp[100];

int longest;

ifp = fopen("words","r"); /* open file for reading */

ofp = fopen("results99", "w"); /* open file for writing */

while (fscanf(ifp,"%s",temp) != EOF)

{

if (strlen(temp)>longest)

{

longest = strlen(temp);

fprintf(ofp,"%s\n",temp);

}

}

fclose(ifp);

fclose(ofp);

}

Notes on the program

  • ifp and ofp are file variables to which we can attach files.

*The fopen function call specifies the file name and the mode in which it is attached to the program

  • fscanf and fprintf are the more general versions of scanf and printf. The additional first parameter is the file variable.
  • We read from the file of words until we reach the end of file (EOF)
  • Every time we encounter a word longer than the longest one we have seen so far we output it to the results file.

Here is a run of the program.

hp9k2 22: gcc ctestc.c

hp9k2 23: a.out

hp9k2 24: cat results99

10th

Aarhus

abalone

abbreviate

aboveground

abovementioned

acknowledgeable

anthropomorphism

arteriolosclerosis

electroencephalogram

electroencephalograph

electroencephalography

More usefully we can let the user supply the names of files at run-time as in the following program that counts the number of lines and characters in a file.

Example 17

#include <stdio.h>

#include <string.h>

main(int argc, char *argv[])

{

if (argc<2)

printf ("Need a file name!\n");

else

{

FILE *fp;

int charcount=0, linecount=0;

char temp[100];

fp = fopen(argv[1],"r"); /* open file for reading */

while (fscanf(fp,"%s",temp) != EOF)

{

linecount++;

charcount+=strlen(temp);

}

fclose(fp);

printf("file %s has %d lines and %d characters\n",

argv[1],linecount,charcount);

}

}

hp9k2 22: gcc ctestd.c

hp9k2 23: a.out ctestd.c

file ctestd.c has 53 lines and 351 characters

hp9k2 24: a.out words

file words has 25143 lines and 181519 characters

Direct access files

When we open a file in the manner of the previous program they can only be read (or written) in a serial manner. In some applications we may wish to read a file randomly in the same way that we access an array

for example.

We have a conceptual file pointer and a function (fseek) that lets us move it to an arbitrary location within a file and another function (ftell) that reports on its current position.

The following program (from Kelley and Pohl) prompts the user for the name of a file then outputs the contents of the file backwards.

#include <stdio.h>

#define MAXSTRING 100

main()

{

char filename[MAXSTRING];

int c;

FILE *ifp;

printf("Input a file name: ");

scanf("%s", filename);

ifp = fopen(filename,"rb"); /* binary mode */

fseek(ifp,0,2); /* move to end of file */

fseek(ifp,-1,1); /* back up 1 character */

while (ftell(ifp) >=0)

{

c = getc(ifp); /* get one character */

putchar(c); /* output it */

if (ftell(ifp)==1) break;

fseek(ifp, -2, 1); /* backup two characters */

}

printf("\n");

}

Here is the program tested on itself

hp9k2 22: gcc ctestf.c

hp9k2 23: a.out

Input a file name: ctestf.c

}

;)"n\"(ftnirp

}

/* sretcarahc owt pukcab */ ;)1 ,2- ,pfi(keesf

;kaerb )1==)pfi(lletf( fi

/* ti tuptuo */ ;)c(rahctup

/* retcarahc eno teg */ ;)pfi(cteg = c

{

)0=> )pfi(lletf( elihw

/* retcarahc 1 pu kcab */ ;)1,1-,pfi(keesf

/* elif fo dne ot evom */ ;)2,0,pfi(keesf

/* edom yranib */ ;)"br",emanelif(nepof = pfi

;)emanelif ,"s%"(fnacs

;)" :eman elif a tupnI"(ftnirp

;pfi* ELIF

;c tni

;]GNIRTSXAM[emanelif rahc

{

)(niam

001 GNIRTSXAM enifed#

>h.oidts< edulcni#

1