0

I am trying to make a program that generates a string given user input, and then passes that string to a function that will change stdin to a dummy file, write the string to the file, use scanf on said file, then delete the file, but I'm having trouble redirecting stdin to the dummy file, any help on the best action that will only extend into the scope of the function?

int scan(const char* __restrict__ _format, ...){
    FILE* original = stdin, *mod = calloc(1, sizeof(FILE));
    mod = freopen("testFile.txt", "w+", stdin);
    fputs(_format, stdin);
    int a, b;
    scanf("%d %d", &a, &b);
    printf("%d, %d", a, b);
//    freopen(orig)
    return 1;
}

void swap(char* a, char* b) {
    if (*a != ' ' && *b != ' ') {
        char temp = *a;
        *a = *b;
        *b = temp;
    }
}

void permiate(char* str, int start, int end){
    int i;
    if(start == end){
        printf("%s\n", str);
    }else{
        for(i = start; i<=end; i++){
            swap(str+start, str + i);
            permiate(str, start + 1, end);
            swap(str + start, str + i);
        }
    }
}

int main(){
    int a, b;
    char str[]  = "1 3";

    //function to put string to stdio
    scan(str);
    scanf("%d %d", &a, &b);
    printf("%d, %d", a, b);
    return 0;
}

after someone pointed out fscanf, a function i was never aware of becasue my teacher never covered it, i have found a working solution to the scan function:

int scan(const char* __restrict__ _format, ...){
    int *a = malloc(sizeof(int)), i = 0;
    FILE *fp1 = fopen("testfile.txt", "w");
    fputs(_format, fp1);
    freopen("testFile.txt", "r", fp1);
    while(fscanf(fp1, "%d", &a[i]) != EOF){
        i++;
        a = realloc(a, sizeof(int)*i);
    }
    for(int j = 0; j < i; j++){
        printf("%d, ", a[j]);
    }
    fclose(fp1);

    return 1;
}

but whenever i give str a value like "1 2 3 4 5 6 ..." or anything that has more than 5 numbers, the 5th number is always 0 if i leave realloc in, if i comment that line out, then it is fine. any idea on what that is about? ps my labs at uni only got to basic uses of arrays, no dynamic memory or anything, so if im using anything wrong it would b greatly appriciated

  • You need to put your code here and show what you have already done. – Noah Dec 16 '19 at 01:51
  • [Rerouting stdin and stdout from C](https://stackoverflow.com/questions/584868/rerouting-stdin-and-stdout-from-c)? – David C. Rankin Dec 16 '19 at 01:55
  • 1
    What on earth are you doing to `mod` in `FILE* original = stdin, *mod = calloc(1, sizeof(FILE));` There is no need to allocate, and it is in fact wrong to allocate a `FILE*` pointer to hold the return from `freopen`. Simply `FILE* original = stdin, *mod;` – David C. Rankin Dec 16 '19 at 03:08
  • @DavidC.Rankin i tried using this, and it does write the string to the file, but when i use scanf, it doesnt ask for input like normal, but it also doesnt read from the file, it just leaves the values alone and doesnt modify them like its supposed to, and i cant seem to undo the freopen() back to normal, any ideas? – mark anthony Dec 16 '19 at 03:17
  • Are you sure you want to `freopen()` `stdin` and not `stdout`? Using `stdout` would allow you to use, e.g. `fputs (_format, stdout)` and write to the filename through `stdout`. There is no limitation on using `stdin` in `man 3 freopen`, it just seems somewhat wonky. – David C. Rankin Dec 16 '19 at 03:27
  • @DavidC.Rankin i am trying to use stdin so when i call scanf() after i write to the file, it behaves like i am scaning after running < file.txt for that function only – mark anthony Dec 16 '19 at 03:51
  • Okay, before you `scanf` try `stdin = freopen(NULL, "r", mod);` (and note, the problem with using `freopen()` to begin with is after you reopen one of the standard streams -- there is no *Portable* way to restore the original) – David C. Rankin Dec 16 '19 at 03:55
  • 1
    This sounds like an [XY Problem](http://mywiki.wooledge.org/XyProblem) (aka [What is the XY Problem?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)). For example, you could use `fscanf()` instead of `scanf()`, and pass `stdin` when you want to read from standard input and a file stream for your newly created file when you want to read from that. Think harder about what your requirements are — and only then about how to solve the problem. – Jonathan Leffler Dec 16 '19 at 04:07
  • @JonathanLeffler thanks, i never heard about fscanf before, and it was just what i needed, thanks a lot :) – mark anthony Dec 16 '19 at 05:10
  • `int *a = malloc(sizeof(int))` allocates 1-`int`. When you `a = realloc(a, sizeof(int)*i);` with `i == 1` you are not increasing the storage on the first iteration and therefore invoke *Undefined Behavior* attempting to store the next value at `a[1]`. – David C. Rankin Dec 16 '19 at 06:33

1 Answers1

0

Alright, I think I understand what you are attempting to do, and it is doable, but I certainly would not recommend it. Whenever you freopen() one of the standard streams, there is no portable way to restore the original standard stream. You can remove original from your function as it will not work. Also do not allocate for mod.

With that said, you can write your scan function as:

int scan(const char* __restrict__ format)
{
    int a, b;
    FILE *mod = freopen ("dat/freopenab.txt", "w", stdin);
    if (!mod) {
        perror ("freopen-mod-write");
        return 0;
    }

    fputs (format, stdin);              /* write to file as stdin */

    stdin = freopen (NULL, "r", mod);   /* reopen file "r" as stdin */
    if (!stdin) {
        perror ("freopen-stdin-read");
        return 0;
    }
    if (scanf("%d %d", &a, &b) != 2) {  /* read values from file */
        fputs ("error: read of int values failed.\n", stderr);
        return 0;
    }
    printf("%d, %d\n", a, b);           /* output resutls */

    return 1;
}

stdin is reopened as file "dat/freopenab.txt" above. The format string is written to the file via the reopened stdin. Then freopen() is called again with NULL as the pathname which allows you to change the mode of the existing stream mod to read and assign the return to stdin (making stdin read from the file)

(note: variable names with leading underscores are best avoided)

A full example would be:

#include <stdio.h>

int scan(const char* __restrict__ format)
{
    int a, b;
    FILE *mod = freopen ("dat/freopenab.txt", "w", stdin);
    if (!mod) {
        perror ("freopen-mod-write");
        return 0;
    }

    fputs (format, stdin);              /* write to file as stdin */

    stdin = freopen (NULL, "r", mod);   /* reopen file "r" as stdin */
    if (!stdin) {
        perror ("freopen-stdin-read");
        return 0;
    }
    if (scanf("%d %d", &a, &b) != 2) {  /* read values from file */
        fputs ("error: read of int values failed.\n", stderr);
        return 0;
    }
    printf("%d, %d\n", a, b);           /* output resutls */

    return 1;
}

int main (void) {

    scan ("12 34\n");
}

Example Use/Output

$ ./bin/freopenab
12, 34

Resulting Output/Input File

$ cat dat/freopenab.txt
12 34

Again, there is no portable way to restore stdin to it original state, though on Linux you can look at using "/dev/tty" or "/dev/stdin". Look things over, and give it a try. Then avoid freopen() unless there is no other way to do what you need to do in favor of just using fopen, fclose, and fopen again.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85