I'm not sure how portable this is, but at least with gcc-6.3 on Linux, you can reassign stdin
to point to different stream, which scanf() will then use transparently as though it is still reading from the terminal. If you want to read from a pre-existing string, that new stream can be opened with something like fmemopen(), which should be available on POSIX systems. This allows you to create a FILE*
from a block of memory, such as the contents of a std::string
.
As an illustration, the following code will scanf()
five values from the string "String with 3.14159 * 2"
as though they had been entered from the terminal:
#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>
int main(int argc, char *argv[])
{ const std::string input("String with 3.14159 * 2");
char s0[16], s1[16], s2[8];
double pi = 3;
int two = -2;
{ FILE *old_stdin = stdin;
FILE* strm = fmemopen((void*)input.c_str(), input.size(), "r");
stdin = strm;
scanf("%s %s %lf %s %d", s0, s1, &pi, s2, &two);
std::cout << "s0=\"" << s0 << "\" s1=\"" << s1 << "\""
<< " pi=" << pi << " s2=\"" << s2 << "\""
<< " two=" << two << std::endl;
stdin = old_stdin;
fclose(strm);
}
scanf("%12s", s0);
std::cout << "Stdin: \"" << s0 << "\"" << std::endl;
return 0;
}
This produces the following output:
s0="String" s1="with" pi=3.14159 s2="*" two=2
before returning stdin
to its normal behaviour, where the second scanf()
waits for input from the terminal.
It would be tempting to try a similar approach using dup2()
(as used here), but it appears that the file-descriptor returned by invoking fileno()
on the value returned from fmemopen()
is not valid (being -1 on my system).