0

I want to use fgets() to simply read a line and strip the newline. Will this work for all cases, on both Windows and UN*X?

fgets(buf, sizeof buf, stdin);
strtok(buf, "\r\n");

Please don't recommend non-standard stuff like GNU's getline(). Thanks in advance!

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Derek
  • 317
  • 2
  • 6

3 Answers3

4

No, if you want cross-platform, do it properly:

fgets (buf, sizeof (buf), stdin);
if (strlen (buf) > 0)
    if (buf[strlen (buf) - 1] == '\n')
        buf[strlen (buf) - 1] = '\0';

You may run in to problems when reading Windows-created files on UNIX (for example) but that will work for its intended purpose, modifying standard input.

If you're worried about multiple calls to strlen:

fgets (buf, sizeof (buf), stdin);
{
    size_t len = strlen (buf);
    if (len > 0)
        if (buf[len - 1] == '\n')
            buf[len - 1] = '\0';
}

By the way, if you're looking for a robust line input solution, which does newline removal, buffer overflow detection, excess line clean-up and uses only standard C, you should take a look at this answer.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Wouldn't that leave a '\r' at the end of the string in the case of Windows, which ends each line with '\r' followed by '\n'? Also, why is it necessary to replace the single call to strtok() with the if statement and two calls to strlen()? – Derek Mar 15 '13 at 04:12
  • @Derek, no, Windows doesn't put a `\r` at the end of lines when inputting (at least for text files). For files, the implementation takes care of the translation. In the case of stdin, you have even less trouble since there's no way the input is coming from a different platform :-) Try it and see for yourself. If you're worried about performance, you can cache the result of `strlen` but modern compilers tend to make this unnecessary. – paxdiablo Mar 15 '13 at 04:14
  • @Derek, because if you input a string with `\r` somewhere in the _middle,_ you will lose some of your line. Good code should do one thing and one thing only, that limits its potential for bugs. You want to remove a newline character from the _end_ of a string if it's there. That's it. Your code should reflect that. – paxdiablo Mar 15 '13 at 04:30
  • Thanks for the explanations. The other commenter seemed to indicate that `strtok(buf, "\n")` eliminates the need for the if statements. Maybe I'm missing something obvious here but `strtok()` doesn't modify the string if there is no '\n' found so there should be no need for the if statements. – Derek Mar 15 '13 at 05:38
  • @Derek, don't make the mistake of thinking there's no `if` statement just because it doesn't appear in _your_ source code. `strtok` itself will need to have one to do its job and, library optimisations aside, will run no faster than a compiled one. In any case, check out the link I gave, it covers much more than just newline removal. – paxdiablo Mar 15 '13 at 05:43
2

No, the internal (interpreted) representation of a newline is always '\n'. So:

 strtok(buf, "\n");

In general, a file needs to be opened in text mode for newline conversion to automatically work:

 text = fopen("text", "r"); // Conversion works
 binary = fopen("binary", "rb"); // Won't work
hdante
  • 7,685
  • 3
  • 31
  • 36
0

Thanks, guys. Ended up writing this wrapper:

void
getstr(char *s, size_t n)
{
    int c;

    if (fgets(s, n, stdin) != NULL) {
        if (s[strlen(s) - 1] == '\n')
            s[strlen(s) - 1] = '\0';
        else
            while ((c = getchar()) != EOF && c != '\n')
               ;
    }
}
Derek
  • 317
  • 2
  • 6