2

I have to write a program in C in which I have to read some values from stdin and also to do it with the quickest function in C. The stdin is preloaded in a form like this:

int,int\n
char\n
int,int,int\n ex...  

I'm asking for help because scanf is too slow for the time requirement of the project and also because I have some difficulties to read because of the ',' that I don't really need and that causes me problems. I've tried with gets or getchar, but I didn't manage to make it work.

karel
  • 5,489
  • 46
  • 45
  • 50
  • 2
    This is going to be hard to answer without seeing specifics. Normally people do not have trouble using getchar, so we maybe should see your use of it to see why its not working in your case. Here are some guidelines for asking good questions: https://stackoverflow.com/help/how-to-ask – Andrew Allaire Jun 24 '21 at 18:25
  • 1
    I very much doubt *scanf is too slow for the time requirement of the project*, anyway ... for user or file input **always** prefer `fgets()` (forget `scanf()` exists). – pmg Jun 24 '21 at 18:30
  • 1
    @Alberto Babo - If it's that time-critical, it's advisable to change the format of the data to be read. – Armali Jun 24 '21 at 18:33
  • The fastest way is `getc()` + a state machine. But: it is a lot of work. – wildplasser Jun 24 '21 at 18:45
  • _"i have to write a program in C"_, but then you go on to explain what constraints you need to include, and even the problems you have, but at no point do you present the work you have done. Please consider including what you have in the form of a [mcve] – ryyker Jun 24 '21 at 18:48
  • 2
    First write the program using `scanf()`, and then demonstrate that it is too slow — measurements! If you've already written the code using `scanf()`, show that code — though there's a risk that the question becomes more suitable for [Code Review](https://codereview.stackexchange.com/) than SO. – Jonathan Leffler Jun 24 '21 at 18:54
  • Under some circumstances I hear it can be significantly faster to use `mmap`. – Steve Summit Jun 25 '21 at 02:34
  • See [this question](https://stackoverflow.com/questions/58403537) for suggestions on `scanf` alternatives. – Steve Summit Jun 25 '21 at 02:36

1 Answers1

0

The fastest way to read stdin ("standard in" - 0 file descriptor) is to use read function from <unistd.h.>:

char buff[1024] = {0}; /* zero-initialize */
ssize_t res = read(0, &buff, sizeof(buff));
/* res is amount of bytes read; -1 if error */

Here is an example of program which reads 1024 bytes of stdin and echoes it to stdout (file descriptor: 1) (no error handling for simplicity):

#include <unistd.h>
#define BUFSIZ 1024

int main() {
    char buff[BUFSIZ] = {0}; /* zero-initialize */
    ssize_t nread = read(0, buff, BUFSIZ);
    /* pass amount of bytes read as a byte amount to write */
    write(1, buff, nread);
    return 0;
}

This is the fastest way to read from stdin because read is native libc wrapper for a kernel syscall. By the way, you can use -O3, or even -Ofast compiler options to make it optimize the code.

Also, keep in mind that read and write are not guaranteed to read/write exactly as many bytes as you want, you should call it in a loop like this:

size_t to_write = sizeof(buff); /* example, can be result of read() */
int fd = 1;

size_t nwrote = 0;
while ((nwrote += write(1, buff, to_write) < to_write) {
    /* pointer arithmetic to create offset from buff start */
    write(fd, buff+nwrote, to_write - nwrote);
}
Vlad Havriuk
  • 1,291
  • 17
  • 29
  • 2
    Your example (toy) program will write extra `'\0'` to *stdout* if input length is less than 1024. – pmg Jun 24 '21 at 18:38
  • @pmg yes, it can be fixed by using `puts` from ``. But this way (with write full buffer) make possible piping binary data to program stdin. – Vlad Havriuk Jun 24 '21 at 18:39
  • 3
    It can be fixed by using the return value of `read()` as an argument to `write()` :-) – pmg Jun 24 '21 at 18:41
  • @pmg: even more than an extra `'0'` ... The rest of the buffer will be output if the input is larger than fits into a single buffer. – wildplasser Jun 24 '21 at 18:41
  • 2
    Note that `read` is not guaranteed to return the amount requested and often won't (at least for files that aren't plain files). It should be called in a loop. – ikegami Jun 24 '21 at 18:43
  • @wildplasser it is true for incorrect use of `puts`, but `write` writes <= `to_write`, so there is not such issue with this – Vlad Havriuk Jun 24 '21 at 18:46
  • 2
    The code that reads the data has to parse its contents according to the format shown in the question. The specification `char\n` is very ambiguous — it might be a single character but more likely is a string. Using `read()` will not respect line boundaries unless the input is a terminal — so using `read()` means that the code must be written to handle multiple lines (and a partial last line) from each `read()` operation. All this is fiddly, and handled automatically by the standard I/O library. – Jonathan Leffler Jun 24 '21 at 18:57
  • @JonathanLeffler yes, the question is ambigious, and by answer solves the task "Read from stdin in the fastest way in C" – Vlad Havriuk Jun 24 '21 at 18:59
  • 1
    It did say "fastest", not "easiest"! – TrentP Jun 24 '21 at 19:25