C Loops

From XPUB & Lens-Based wiki

How to use the programs on this page

Save the sample code as a file ending in .c, for instance "readlines.c", then from the command line, cd to the directory containing the file, and type:

gcc readlines.c -o readlines

or to include debugging info (for use with gdb/ddd)

gcc -g readlines.c -o readlines


Then to run the program and feed it some text (such as itself), you could use:

./readlines < readlines.c

or perhaps, something like (just make sure the file is plain text):

./readlines < ~/Documents/alice.txt

Reading stdin line by line

fgets is a function that reads a line of input from a file. It takes three arguments (parameters):

fgets(line, maxchars, file)

1. line: the name of a variable in which to store the result, 2. maxchars: the maximum number of characters possible in a line (the function will never try to read more than this many characters, even if a line is longer), 3. file: the name of the file to read from, here we use stdin to read from whatever is piped to this program.

fgets returns a value indicating whether or not it was able to read any input. In this way, it's possible to use as the condition of a while loop to keep reading each line until no more input is available (at which time fgets returns 0 and the while loop stops).

   // read all of stdin line by line
   while (fgets(line, MAXLINE, stdin)) {
       // do something with line
   }
   // loop stops when there's no more input

The following C program reads the content of stdin line by line and simply re-outputs it through unchanged. In this way, this could be seen as the basis for writing some sort of text filter program. Note how MAXLINE is defined as a compiler directive to tell C how much space to create for the line variable, both (1) when declaring the variable, and (2) when calling the fgets function.

#include "stdio.h"
#define MAXLINE 1000

int main () {
    char line[MAXLINE];

    while (fgets(line, MAXLINE, stdin)) {
        printf("%s", line);
    }

    // returning 0 from main is the convention to indicate that the program finished normally
    return 0;
}

The following program prints the message "line is ??? characters long" with ??? filled with the result of calling the strlen function. What do you notice about the value strlen returns, is it correct (and if not, could you guess why that is?) Note how the code includes the string.h header file to make use of the strlen function defined within it.

#include "stdio.h"
#include "string.h"
#define MAXLINE 1000

int main () {
    int i=0;
    int linelen;
    char line[MAXLINE];
    while (fgets(line, MAXLINE, stdin)) {
        linelen = strlen(line);
        printf("line is %d characters long\n", linelen);
    }
    return 0;
}

Exercise: Line Numbering

Exercise: Write a program that adds line numbers to each line given to it via stdin.

The first argument to printf is the "format" string, which works like a kind of template. It includes support for "padding" values:

printf("%04d\n", 27);
printf("%06d\n", 27);

would output:

0027
000027

Exercise: Use string padding to pad the line numbers of your line numbering program.

Processing each line character by character

To do some simple filtering of each line, it's possible to use a nested loop to do something with each character in a line.

#include "stdio.h"
#include "string.h"
#define MAXLINE 1000

int main () {
    char line[MAXLINE];
    int linelen;
    int i;
    
    while (fgets(line, MAXLINE, stdin)) {
        linelen = strlen(line);
        i=0;
        while (i<linelen) {
            printf("%c ", line[i]);
            i++;
        }
        printf("\n");
    }

    return 0;
}

The same program, with a for loop instead of a while.

#include "stdio.h"
#include "string.h"
#define MAXLINE 1000

int main () {
    char line[MAXLINE];
    int linelen;
    int i;
    
    while (fgets(line, MAXLINE, stdin)) {
        linelen = strlen(line);
        for (i=0; i<linelen; i++) {
            printf("%c ", line[i]);
        }
        printf("\n");
    }

    return 0;
}

Exercise: Punctuation only filter

Exercise: The ctypes.h header includes a function called ispunct, which returns True if a given character is punctuation. Modify the code above to have a program that prints only the punctuation of a file (it a character is not punctuation, print a space.

 if (ispunct(c)) {
   // do something!
 }