How to print both to stdout and file in C

I read this topic, but his problem maybe different from mine Writing to both stdout & a file

I want to write a function, that function need to print out to both stdout and a file. My C program gets user input by scanf.

I intend to write a function like printf but I don't really know how:

I tried this, but it only can work with "pure" string, can't convert %d, %.*lf (my print function only need two conversions)

void dupPrint(FILE *fp,char *string)
{
    printf("%s",string);
    fprintf(fp,"%s",string);

    return;
}

I tried dup2 and freopen but they didn't work for me.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    int i;
    int file = open("input3.txt", O_APPEND | O_WRONLY);
    if(file < 0) return 1;

    if(dup2(file,1) < 0) return 1;

    printf("Redirect to file!\n");
    printf("enter i : ");
    scanf("%d",&i);



    return 0;
}

This dup2() tutorial only print to file.

I also tried tee, but may be it not work because I have to get input from user (if work, it's not "fair" because tee isn't in my program).

I think implement a printf-like will solved problem but I don't know how to convert .*lf (print out double with user-enter precision)

#include <stdio.h>
#include <stdarg.h>
void dupPrint(FILE *fp,char *fmt,  ...)
{
    va_list ap;
    char *p, *sval;
    int ival;
    double dval;

    va_start (ap, fmt); //make ap point to 1st unnamed arg
    for(p = fmt; *p; p++)
       {
           if (*p != '%') {
               putchar(*p);
               continue;
           }
           switch (*++p) {
               case 'd':
                   ival = va_arg(ap, int);
                   printf("%d", ival);
                   break;
               case '.*lf' //?????
           }
       }       

}

Can anyone suggest a solution for my problem?


Solution 1:

Fortunately, you don't need to. You just want to use the v variants of printf and fprintf that take a va_list instead of your passing arguments directly:

void tee(FILE *f, char const *fmt, ...) { 
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    va_start(ap, fmt);
    vfprintf(f, fmt, ap);
    va_end(ap);
}

Solution 2:

You can implement your dupPrint function using vfprintf and va_list/ va_start / va_end.