简体   繁体   中英

C Program doesn't end after giving the correct output

So I'm trying to do a program that reads a sequence of numbers separated by spaces and new lines. The output should be the same sequence, but erasing unnecessary zeros(The sequence of charachters 'EOF' ends the program). Per example

  1. 01492 102934 should come out as 1492 102934
  2. 9312 0 01923 should come out as 9312 0 1923
  3. 0001249 0000 should come out as 1249 0

Well I've achieved that purpose but have come across a roadblock. The program doesn't exit unless I type the EOF sequence. Maybe it's because I have a while(1) running that gives an infinite loop. But when I try to delete it the program doesn't even print at all. I'm still learning this is for a school project. Any help would be apreciated!

Here's the code:

#include <stdio.h>
int main(){
char c;
int i=0;
while(1){
    c=getchar();
    if (i==0){
        if(c=='0'){
            while (c=='0'){
            c=getchar();
            }
        }
        printf("%c",c);
        i=i+1;
    }
    else if (c==' '){
        printf("%c",c);
        c=getchar();
        if(c=='0'){
            while (c=='0'){
            c=getchar();
            }
        }
        printf("%c",c);
    }
    else if (c=='E'){
        c=getchar();
        if (c=='O'){
            c=getchar();
            if(c=='F'){
                printf("\n");
                return 0;
            }
        }
    }
    else{
        printf("%c",c);
    }
}

}

The important stuff:

int c; // IMPORTANT, cannot be char
while (1) {
    c = getchar();
    if (c == EOF) break; // exit loop
    // ...
}

There has to be some way to tell the program to exit.
With this, the program will exit on the letter x or two consecutive newlines or entering END .
getchar will return EOF when there is nothing left to read from a file. That can be simulated from stdin ( the keyboard) with ctrl + z on Windows or ctrl + d on Linux.

#include <stdio.h>
#include <string.h>

int main ( void) {
    char done[4] = "";
    int c = 0;
    int prior = 0;
    int reading = 0;
    int zero = 1;

    while ( EOF != ( c = getchar ( )) && 'x' != c) {
        if ( '\n' == c && '\n' == prior) {
            break;
        }
        if ( c >= '0' && c <= '9') {
            reading = 1;
            if ( '0' != c) {
                zero = 0;
            }
            if ( ! zero) {
                putchar ( c);
            }
        }
        else {
            if ( reading) {
                if ( zero) {
                    putchar ( '0');
                }
                if ( ' ' == c || '\n' == c) {
                    putchar ( c);
                }
                else {
                    putchar ( ' ');
                }
            }
            reading = 0;
            zero = 1;
        }
        prior = c;

        done[0] = done[1];
        done[1] = done[2];
        done[2] = c;
        done[3] = 0;
        if ( 0 == strcmp ( done, "END")) {
            break;
        }
    }
    putchar ( '\n');
    return 0;
}
  1. getchar() returns an int, not a char. If it only returned a char, there would be no way for it to return a value that indicates end of file, since all char values are valid and can't be used for another purpose.

    A motivating example in decimal system may be: A function checks the temperature returns a two-digit number. Any temperature between 0 and 99 is valid. How do you report errors when the thermometer is disconnected? You have to return a number with more digits, and use a special value like UNPLUGGED = 100 .

    But int is a wider type: it has many more values than char, and the “extra” values can be used to indicate some special condition that means “hey, this is not a valid character, but something else I had to tell you”.

  2. getchar() returns the EOF constant upon failure (any failure), for example if no more input is available. There's nothing sensible you can do even if the reason for the failure other than end of input. You should end processing at the first EOF.

Thus, change the type of c to int, and every time you call getchar() , you must check that its value is not EOF, and return when you encounter it.

The nested structure of your loops means that EOF checking has to be repeated all over the place. There are other ways to structure the code to keep this check in one place, but, admittedly, the nested loops have at least the potential to exploit the branch predictor, whereas a single getchar followed by a state-machine style switch statement will make it perform potentially worse. None of this matters in a simple homework problem, but it's something to keep in mind. In any case, performance has to be benchmarked - no other way around it.

Try this code, I think it does what you requested:

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

static int getLine(char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf("%s", prmpt);
        fflush(stdout);
    }
    if (fgets(buff, sz, stdin) == NULL)
        return -2;
    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff) - 1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? -1 : 0;
    }
    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff) - 1] = '\0';
    return 0;
}

int* convert2numbers(char* arr, int size) {
    int i;
    int j;
    int k;

    char token[100];
    int* numbers;
    int last_space = 0;
    int index = 1;
    int amount = 1;
    // Count the amount of tokens.

    for (i = 0; i < size; ++i) {
        if (arr[i] == ' ') {
            ++amount;
        }
    }
    numbers = (int *)malloc(amount * sizeof(int));
    numbers[0] = amount;

    for (j = 0; j <= size; ++j) {
        if (arr[j] == ' ' || arr[j] == '\0') {

            // Copy token from input string.
            for (k = 0; k < j; ++k) {
                token[k] = arr[k + last_space];
            }
            token[j] = '\0';
            numbers[index] = atoi(token);
            // Clear the token and continue.
            memset(token, '\0', sizeof(token));
            last_space = j;
            ++index;
        }
    }
    return numbers;
}

int main(void) {
    int i;
    int size;
    int* numbers;
    int amount;
    char input[100];
    char help[] = "Numbers> ";

    printf("Input numbers below or press enter to exit!\n");
    while (1) {
        getLine(help, input, sizeof(input));
        // If input is empty exit.
        if (input[0] == '\0') {
            break;
        }
        size = strlen(input);
        numbers = convert2numbers(input, size);
        amount = numbers[0];
        for (i = 1; i < amount + 1; ++i) {
            printf("%d ", numbers[i]);
        }
        printf("\n");
    }
    return 0;
}

When run with these inputs this code outputs:

Input numbers below or press enter to exit!
Numbers> 01492 102934
1492 102934
Numbers> 9312 0 01923
9312 0 1923
Numbers> 0001249 0000
1249 0

Also if you press enter in console, it exits, as to escape the while(1) loop, easily.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM