0

I wanted to make my own getline() like function in C and this is what I came up with:

void getstring(char *string)
{ 
    fgets(string,STRING_LENGTH,stdin);
    string[strlen(string)-1]='\0';
}

It's good enough if number of typed characters doesn't exceed STRING_LENGHT (in this case 100) but once it does, everything above it is stays in buffer and jumps on next read string.

I've already tried to flush buffer by using following procedure:

void flush_buffer()
{
    char c;
    while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;
}

It does its job in described case, but once the string doesn't exceed STRING_LENGHT I need to type anything before moving on.

Is there any way to read string such that I know whether STRING_LENGHT is exceeded or not so I can condition the flushing?

If there's a better way to make getline() like function, it would be even better.

Igor
  • 163
  • 6
  • First make sure your system doesn't already have a [`getline` function](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html). – Some programmer dude Jan 12 '19 at 17:34
  • 1
    And there is a very good way to know if the max amount of characters was read with [the `fgets` function](https://en.cppreference.com/w/c/io/fgets): Is there a newline or not in the string? You also need to handle errors and the case where no newline was actually read. – Some programmer dude Jan 12 '19 at 17:36
  • @Someprogrammerdude Why should make sure the system doesn't have one already? I assume he's doing this for educational purposes, to learn how such a function would be written. – Barmar Jan 12 '19 at 17:54
  • Your function isn't anything like the standard [`getline()`](https://linux.die.net/man/3/getline). The `string` argument should be `char **`, so that the function can call `malloc()` and `realloc()` to allocate enough space. – Barmar Jan 12 '19 at 17:56
  • The whole point of `getline()` is that the line can be any length, there's no predefined `LINE_LENGTH` limit. The caller doesn't have to allocate the buffer, the function does it itself. – Barmar Jan 12 '19 at 18:00

1 Answers1

1

Is there any way to read string such that I know whether STRING_LENGHT is exceeded or not so I can condition the flushing?

The amount of character read by fgets() will not meet nor exceed STRING_LENGHT.

But to find out if more of the line remains unread, the usual way it to detect if the string read is of maximally length and does not include a '\n'.

// return EOF, 0 (not all line was read) or 1 (all the line was read)
int getstring(char *string) { 
  if (fgets(string,STRING_LENGTH,stdin) == NULL) {
    return EOF;
  }
  int retval = 1;
  size_t sz = strlen(string);
  if (sz + 1 == STRING_LENGTH && string[sz-1] != '\n') {
    int c;
    while((c = getchar()) != '\n' && c != EOF) {
      retval = 0;
    } 
  }
  return retval;
}

More robust to pass in the size

// int getstring(char *string) { 
//  if (fgets(string,STRING_LENGTH,stdin) == NULL) {

int getstring(char *string, int sz) { 
  if (fgets(string,sz,stdin) == NULL) {

But to be the same as getline(), more changes are needed. @Barmar


OP's flush_buffer() is an infinite loop when char is unsigned and end-of-file is true. Use int

void flush_buffer(void) {
    // char c;
    int c;
    while((c = getchar()) != '\n' && c != EOF)
        /* discard */ ;
}

string[strlen(string)-1]='\0'; is undefined behavior (UB) should the first character read by fgets() is a null character - a nice little exploit to avoid.

fgets(string,STRING_LENGTH,stdin);
if (*string) {
  string[strlen(string)-1]='\0';
}

See also Removing trailing newline character from fgets() input.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • As well as Barmar's observations, note that `getline`, unlike `fgets`, permits the input to include NUL characters, since it explicitly returns the number of characters read. This makes it impossible to correctly implement using `fgets`. – rici Jan 12 '19 at 19:13
  • @rici Re `fgets()`, null characters and "impossible to correctly implement", see [Is it possible to read null characters correctly using fgets or gets_s?](https://stackoverflow.com/q/50160039/2410359). `fgets()` is not the best tool concerning null characters - yet "impossible" is debatable. – chux - Reinstate Monica Jan 12 '19 at 19:24
  • Ok, "without heroic effort" :-) – rici Jan 12 '19 at 19:34