简体   繁体   中英

Scanf ignoring new line character when scanning from input file

I'm working on a program that intends to read multiple lines of strings and sort them into arrays of strings.

I'm trying to read the first line manually and the loop is supposed to exit once it reads the new line character '\\n'. This works when I manually enter the strings in terminal, but reading from in input file (through terminal), it does not read the newline character and the loop continues.

char array[20][20];
char letter = 'a';
for (int i = 0; letter != '\n'; i++) {
    scanf("%s",array[i]);    //store the word into an array of words
    printf("Scanned %s\n",array[i]);
    scanf("%c",&letter);     //look for space or new line character
}

It works when I manually enter this text, but not when reading it from a file:

word word1 word2
word3 word4 word5

When inputting manually, I would enter the first line, "word word1 word2", hit enter, and it would scan that line and end the program.

When using the file, it returns:

$ ./potw18 < input.txt
Scanned word
Scanned word1
Scanned word2
Scanned word3
Scanned word4
Scanned word5
Scanned
Scanned ▒
Scanned
Scanned ▒
Scanned
Scanned ▒8.▒
Scanned
Scanned ▒8.▒
Scanned

And continues on.

I predict that the file input.txt has:

  • whitespace (other than a newline) at the end of the first line, and
  • is similar or simply doesn't have a newline at the end of the second line

Because of the first point, the scanf("%c",&letter); reads something other than a newline (a space, for example) so the program continues on to the second line.

After reading the last word, there's nothing in the file for scanf() to read, so it returns an error - every time that it's called. The program doesn't check for those errors and blindly trudges on.

Personally, I'm not a huge fan of using scanf() except for quick-n-dirty one off code. It's too error prone for arbitrary input. I'd suggest reading lines into a buffer then using sscanf() , strtok() or something even better to parse from there (basically, similar to what @RoadRunner's answer says).

You can just read each line with fgets(3) , until it returns NULL , which indicates a line was not read. You could also use getline(3) to do this, which is a POSIX C function designed for reading lines efficiently. In terms of getting each words, you can use strtok(3) or strchr(3) to parse each word at each space on the line, and safely add it to your 2d char array. Using scanf() only makes it harder to do this, as justified thoroughly in @Michael Burr's post.

Here is a basic example of reading lines from a file with stdin , and storing the found words in an array of strings:

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

#define NUMWORDS 20
#define WORDLEN 20
#define LINESIZE 100

#define WORDSIZE(x) (sizeof x[0])
#define ARRSIZE(x) (sizeof x / sizeof x[0])

int main(void) {
    char array[NUMWORDS][WORDLEN];
    char line[LINESIZE];
    char *word = NULL, *currline = NULL;
    const char *delim = " \n";
    size_t numwords = 0;

    while (fgets(line, sizeof line, stdin) != NULL) {
        currline = line;

        word = strtok(currline, delim);
        while (word != NULL) {
            if (numwords < ARRSIZE(array) && strlen(word) < WORDSIZE(array)) {
                strcpy(array[numwords], word);
                numwords++;
            }
            word = strtok(NULL, delim);
        }
    }

    for (size_t i = 0; i < numwords; i++) {
        printf("array[%zu] = %s\n", i, array[i]);
    }

    return 0;
}

Note The above code uses strtok() m which is a string function that you have to be careful with. It might be better to use strchr() here.

Use scanf to scan for a character and test to see if the character is whitespace using isspace . break when the character is newline.
If the character is not whitespace, use ungetc to replace the character into the input stream and then scanf the word. %19s prevents scanning too many characters into the array.

#include <ctype.h> //header for isspace

while ( scanf ( "%c", &letter) == 1) {
    if ( isspace ( letter)) {
        if ( letter == '\n') {
            break;
        }
    }
    else {
        ungetc ( letter, stdin);//replace letter in input stream
        if ( scanf ( "%19s", array[i]) == 1)
        {
            i++;
            if ( i >= 20) {
                break;
            }
        }
    }
}
char array[20][20];
char letter = 'a';
for (int i = 0; letter != '\n'; i++) {
   gets(array);    //store the word into an array of words
   letter = array[i];
   scanf("%c",&letter);    
}

By using gets it should work.

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