Elaborating on the title, I'm trying to complete an exercice in K.N. King's C Programming: A Modern Approach which requires me to accomplish the task in the quote below. My idea works, but the program does not return control to the OS. I've nailed the problem down to the do/while loop, which does not seem to reach the EOF mark. So how should I go about detecting the end of file? Thanks in advance!

Write a program that reads a series of phone numbers from a file and displays them in a standard format. Each line of file will contain a single phone number, but the numbers may be in a variety of formats. You may assume that each line contains 10 digits, possibly mixed with other characters (which should be ignored). For example, suppose that the file contains the following lines:

404.817.6900
 (215)  686-1776
312-746-6000
877 275 5273
6173434200

The output of the program should have the following appearance:

(404) 817-6900
(215) 686-1776
(312) 746-6000
(877) 275-5273
(617) 343-4200

Have the program obtain the filename from the command line

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void terminate(const char *message);

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

    FILE *fp;
    char str[31], ch;
    int i = 0, p1, p2, p3;

    if(argc != 2)
        terminate("usage: pp2217 <filename>\n");

    if(!(fp = fopen(argv[1], "rb")))
        terminate("cannot open file for reading\n");

    do {

        while((ch = getc(fp)) != '\n')
            if(isdigit(ch))
                str[i++] = ch;
        str[i] = '\0';
        i = 0;

        sscanf(str, "%3d%3d%4d", &p1, &p2, &p3);
        printf("(%3d) %3d-%4d\n", p1, p2, p3);
    } while(ch != EOF);

    fclose(fp);

    return 0;
}

void terminate(const char *message) {

    fprintf(stderr, "%s", message);
    exit(EXIT_FAILURE);
}

Edited 6 Years Ago by creeps: n/a

Have you tried testing the return from sscanf() ?

When it return anything less than 1, you should be at the end of the file - or at least something stopped sscanf() from working right.

It is frustrating how you have to "dance around" to do such a simple thing.

Comments
I love to hate the last sentence :)

>char str[31], ch;
Let's start with this common error. EOF is guaranteed to be a negative quantity, but char may be unsigned. getc returns int for a reason, and that reason is to guarantee that EOF is representable regardless of the signedness of vanilla char.

>while((ch = getc(fp)) != '\n')
Your loops are contradictory and ultimately infinite. The outer loop waits for EOF, but the inner loop (which is your actual reading loop) doesn't stop when it sees EOF.

Comments
THE answer

It is frustrating how you have to "dance around" to do such a simple thing.

Yeah, I've been there an awful lot of times so far :(

>while((ch = getc(fp)) != '\n')
Your loops are contradictory and ultimately infinite. The outer loop waits for EOF, but the inner loop (which is your actual reading loop) doesn't stop when it sees EOF.

This is one of the answers which make me hate myself for not seeing such a trivial error. I guess I need some more practice :(

After implementing the changes suggested by Narue, the program works as intended. Thanks a lot!

>It is frustrating how you have to "dance around" to do such a simple thing.
Stream input is unintuitive. As an implementer of the standard library, I consider myself to be above average in terms of proficiency. But the behavior of stream I/O still catches me off guard more than any other aspect of C. In fact, I'm often amazed that beginners can manage at all. ;)

This question has already been answered. Start a new discussion instead.