user3408678
user3408678

Reputation: 155

fprintf not writing to file, despite fclose()

As the title states I'm trying to write to a file with fprintf, and I've searched on Stack Overflow for why it wouldn't be writing to file. What I've found is that it holds it in memory until you close the file(right?), hence the usage of fclose(). However, it's still not working for me.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>


void printHelp()
{
    printf("Usage: fstring [ char ] [ amount ] Optional:[ outfile ]\n"
           "Example: fstring A 100 out.txt\n");
    exit(1);
}

char *f_string(const char *s, int t)
{
    int i; char *dst = malloc(t * strlen(s) + 1);
    for(i = 0; i < t; i++) {
        strcat(dst, s);
    }
    return dst;
}


int main(int argc, char *argv[])
{
    char c; char *file;

    while((c = getopt(argc, argv, "f:")) != -1)
        switch(c) {
        case 'f':
            file = optarg;
            break;
        default:
            printHelp();
            return 1;
        }

    if(argc < 3) {
        printf("You need at least two arguments!\n");
        return 1;
    }

    char *res = f_string(argv[1], atoi(argv[2]));
    FILE *f = fopen(file, "w+");
    if(!f) {
        puts(res);
        exit(0);
    } else {
        fprintf(f, "%s", res);
    }

    fclose(f);
    free(res);
    return 0;
}

What I really don't understand is why the above code doesn't work, but this does just fine:

int main(int argc, char *argv[])
{
    char line[80];

    if(argc != 6) {
        fprintf(stderr, "You need to give 5 arguments!\n");
        return 1;
    }

    FILE *in;
    if(!(in = fopen("spooky.csv", "r"))) {
        fprintf(stderr, "File %s doesn't exist!", in);
        return 1;
    }

    FILE *file1 = fopen(argv[2], "w");
    FILE *file2 = fopen(argv[4], "w");
    FILE *file3 = fopen(argv[5], "w");

    while(fscanf(in, "%79s", line) == 1) {
        if(strstr(line, argv[1]))
            fprintf(file1, "%s\n", line);
        else if (strstr(line, argv[3]))
            fprintf(file2, "%s\n", line);
        else
            fprintf(file3, "%s\n", line);
    }

    fclose(file1);
    fclose(file2);
    fclose(file3);
    return 0;
}

The second code works just fine writing to files. Hoping someone can enlighten me. Thanks.

Upvotes: 2

Views: 3384

Answers (3)

baf
baf

Reputation: 4661

Use optind to find out where non-optional arguments start.

int main(int argc, char *argv[])
{
    char c; char *file;

    while((c = getopt(argc, argv, "f:")) != -1)
        switch(c) {
        case 'f':
            file = optarg;
            break;
        default:
            printHelp();
            return 1;
        }


    int index = optind;
    if(argc - index + 1 < 3) {
        printf("You need at least two arguments!\n");
        return 1;
    }
    char *res = f_string(argv[index], atoi(argv[index + 1]));
    FILE *f = fopen(file, "w+");
    if(!f) {
        puts(res);
        exit(0);
    } else {
        fprintf(f, "%s", res);
    }

    fclose(f);
    free(res);
    return 0;
}

Upvotes: 1

Anto Jurković
Anto Jurković

Reputation: 11258

From man page of getopt(): By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end.

If your call your executable with options Abc 10 -f out.txt then after getopt processing argv[1] will be -f and argv[2] will be out.txt. So you have to change line

char *res = f_string(argv[1], atoi(argv[2]));

to

char *res = f_string(argv[3], atoi(argv[4]));

Otherwise, help usage is completely wrong because according to code nothing is optional.

Function f_string() has to be corrected:

char *f_string(const char *s, int t)
{
    int i; 
    char *dst = malloc(t * strlen(s) + 1);
    dst[0] = '\0';  // <-----

    for(i = 0; i < t; i++) {
        strcat(dst, s);
    }
    return dst;
}

Without proper initialization strcat() could start at the middle of dst.

Upvotes: 2

Logan Ding
Logan Ding

Reputation: 1771

The root cause is that the arguments are messed up.

After you called getopt, the point to arguments argv has been manipulated and no more pointed to the original argument. So afterwards when you use argv[1], argv[2] for fstring function, they are not the arguments you passed to the main function.

The simplest correction is to store the arguments in temporary variables before passing argv to getopt.

int main(int argc, char *argv[])
{
    char c; char *file;

    char *v1 = argv[1];
    int v2 = atoi(argv[2]);


    while((c = getopt(argc, argv, "f:")) != -1)
        switch(c) {
        case 'f':
            file = optarg;
            break;
        default:
            printHelp();
            return 1;
        }

    if(argc < 3) {
        printf("You need at least two arguments!\n");
        return 1;
    }

    char *res = f_string(v1, v2);
    FILE *f = fopen(file, "w+");
    if(!f) {
        puts(res);
        exit(0);
    } else {
        fprintf(f, "%s", res);
    }

    fclose(f);
    free(res);
    return 0;
}

Upvotes: 3

Related Questions