1

I want to parse input such as:

1 2 3\n4 5 6\n7 8 9\n\n

and for each row save each value in int ant print it to stdout until I get an empty line, so for this example I would get:

1 2 3
1 2 3
4 5 6
4 5 6
7 8 9
7 8 9

I've tried something like

int n1, n2, n3;
while(scanf ("%d %d %d\n", n1, n2, n3) != EOF) {
    printf("%d %d %d\n", n1, n2, n3);
    fflush(stdout);
}

but it doesn't seem to work. Is there any simple way to do that?

2 Answers 2

3

scanf cannot achieve what you are trying to do because it keeps reading until the condition is met, and %d specifier will ignore '\n' newline character, I propose this code

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

int  main()
{
    int n1, n2, n3;
    char line[64];

    /* read at least 63 characters or unitl newline charater is encountered with */
    /*    fgets(line, sizeof line, stdin) */
    /* if the first character is a newline, then it's an empty line of input */
    while ((fgets(line, sizeof line, stdin) != NULL) && (line[0] != '\n'))
    {
        /* parse the read line with sscanf */
        if (sscanf(line, "%d%d%d", &n1, &n2, &n3) == 3)
        {
            printf("%d %d %d\n", n1, n2, n3);
            fflush(stdout);
        }
    }
    return 0;
}

While this code works it's not robust, since it will fail in the case commented below by WhozCraig, so this is a way to do it that will keep you safe from the problem

#include <stdio.h>
#include <string.h>
#include <ctype.h> /* for isspace */

int isEmpty(const char *line)
{
    /* check if the string consists only of spaces. */
    while (*line != '\0')
    {
        if (isspace(*line) == 0)
            return 0;
        line++;
    }
    return 1;
}

int  main()
{
    int n1, n2, n3;
    char line[64];

    while ((fgets(line, sizeof line, stdin) != NULL) && (isEmpty(line) == 0))
    {
        if (sscanf(line, "%d%d%d", &n1, &n2, &n3) == 3)
        {
            printf("%d %d %d\n", n1, n2, n3);
            fflush(stdout);
        }
    }
    return 0;
}
Sign up to request clarification or add additional context in comments.

7 Comments

It doesn't work as well. For this input I'm getting > 1 2 3 > 4 5 6 < 1 2 3 > 7 8 9 < 4 5 6
@iharob: from the link you posted: "The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. " (In the return values section.)
I didn't see scanf I somehow saw, sscanf.
But do I really get EOF or just "\n"? I want to stop reading after two "\n" in a row.
Note, the OP may consider the case of "\n \n" vs "\n\n". The former will not evaluate (line[0] != '\n') as true and thusly will fall into the inner if(scanf... check (which will obviously fails to parse three int). fgets() does not strip leading whitespace like formatted scanf does. Not a big deal unless you're relying on counting the number of entrances into the while-body as lines-parsed. Parsing correct data is trivial; its the incorrect data that is a real PITA to deal with.
|
0

I didn't really like any of the answers provided since they don't also capture the input. I needed to capture the entire read contents and process them in batch. So here's what I came up with:

char * readFromFileUntilBlankLine(FILE *in) {
    int growBy = 1000;
    int allocatedSize = growBy;
    char *buffer = malloc(allocatedSize * sizeof(char));
    strcpy(buffer, "");

    char * line = NULL;
    size_t len = 0;
    ssize_t read = 0;

    while ((read = getline(&line, &len, in)) != EOF) {
        // Are we done? Is this blank?
        if (line[0] == '\n') {
            free(line);
            return buffer;
        }

        // Ensure there is enough space in buffer for line
        int newSize = strlen(buffer) + read + 1;
        if (newSize > allocatedSize) {
            allocatedSize = newSize + growBy;
            buffer = realloc(buffer, allocatedSize * sizeof(char));
        }
        strcat(buffer, line);

        free(line);
        line = NULL;
    }

    if (line) {
        free(line);
    }

    return buffer;
}

This suffers from the same "\n \n" problem discussed in a previous response, but was sufficient for my needs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.