How to determine if fgets stopped before all lette

2019-07-25 00:28发布

问题:

I do something like this:

char buf[100];              
int n = 0;                  
char save[100][100];        

while (fgets(buf,100, file)!=NULL) {
    strcpy(save[n], buf);
    printf("%s",buf);
    n++;
}

I opened a FILE = *file with error handling before. I only want to read the lines that have less than or equal to 100 characters. Those that feature more characters, I want to ignore and write some special message to the "save" array or to the perror or stout stream.

However, how can I possibly know whether I got exactly 100 characters or my fgets has simply stopped reading at its limit?

How can I know whether I got more than 100 in the first place?

回答1:

First let us assume that fgets() is not going to read a null character. If it does, the following method may be insufficient.

I only want to read the lines that have less than or equal to 100 characters. Those that feature more characters, I want to ignore and write some special message to the "save" array

Problem 1. Is the '\n' or Enter part of the 100 characters? Let us assume it is not.

OP appears to still want to read the line, be it longer or shorter than 100 or COLS characters, it is just a question of what to do with it then.

Recommend a buffer of COLS+3. One for the null character, one for the '\n' and one for extra long line detection.

#define ROWS 100
#define COLS 100
char save[ROWS][COLS+1];  // +1 for \0      
char buf[COLS + 3];              
int n = 0;                  

while (n < ROWS && fgets(buf, sizeof buf, file)!=NULL) {
  size_t len = strlen(buf);
  bool EOLorEOFfound = false;

  // lop off potential \n
  if (len > 0 && buf[len - 1] == '\n') {
    buf[--len] = '\0';
    EOLorEOFfound = true;
  }

  // if line is too long ...
  if (len > COLS) {
    // consume rest of line
    while (!EOLorEOFfound) {
      int ch = fgetc(file);
      EOLorEOFfound = ch == '\n' || ch == EOF;
    }
    // write some special message to the "save" array
    assert(COLS >= 3);
    strcpy(save[n], "***");
  } 
  // Line not too long
  else {
    strcpy(save[n], buf);  // or memcpy(save[n], buf, len+1);
    printf("%s\n", buf);
  }
  n++;
}


回答2:

Don't use fgets(), use getline(). With fgets(), once you read a too-long line (however you identify it), you'll have to keep reading that line and discarding it until you reach a new line. In other words, you have a need to track state, which isn't needed if you use getline() since it gives you the entire line, and tells you how long it is:

FILE *fp = // fopen() however you need to

char *lineArray[ MAX_LINES ];
int ii = 0;

char *line = NULL;
size_t len = 0UL;

// loop until getline() fails
for ( ;; )
{
    ssize_t lineLen = getline( &line, &len, fp );
    if ( lineLen == -1L )
    {
        break;
    }

    if ( lineLen > 100L )
    {
        // handle too-long line
    }
    else
    {
        lineArray[ ii ] = strdup( line );
        ii++;
    }
}

You might want to strip any trailing newline characters from each line before copying the line to the array.

Note that I used strdup() to copy the line - that's not a C Standard function, but it is POSIX.



回答3:

You could check the string length and the last character. If the length is 99 characters and the last character is not a newline, then there are more characters on the line that fgets didn't read (though the remaining characters might just be the newline).

If fgets read the whole line, either the length of the string will be less than 99 or the last character will be a newline (which fgets always adds if it fits in the buffer).

Note that I say 99 characters, as an array of 100 character will only fit 99 characters plus the string terminator character '\0'. If you want to read up to (and including) 100 characters, your buffer needs to be 101 characters large.

Example showing it in "action". The first two outputs is from reading lines that are longer, and fgets didn't read all of the line. The second two lines of output are when fgets read the whole lines.



标签: c file fgets