skip to Main Content

I’ve written this program:

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

int concatenate(int argc, char *argv[]);

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

    concatenate(argc, argv);
    return 0;
}

int concatenate(int argc, char *argv[]) {
    FILE *temp;
    int sz;
    for (int i = 1; i < argc; i++) {
        if ((temp = fopen(argv[i], "r")) == NULL) {
            fprintf(stderr, "Error while opening file %s", argv[i]);
            exit(EXIT_FAILURE);
        } 

        fseek(temp, 0L, SEEK_END);
        sz = ftell(temp);
        rewind(temp);

        fwrite(stdout, 1, sz, temp);
        fclose(temp);
    }
}

And I want to know why the program is printing rare characters to stdout and how to solve the problem to no prevent to commit it in the future. Thank you in advance.

By the way, I’m passing normal .txt files to the program and I’m currently working on Ubuntu.

2

Answers


  1. The program has undefined behavior here:

        fwrite(stdout, 1, sz, temp);
    

    The prototype for fwrite is:

    size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb,
                  FILE * restrict stream);
    

    Your call attempts to write to the stream pointed to by temp a number of bytes equal to 1 * sz pointed to by stdout.

    • Writing to a stream open for reading has undefined behavior. It is unlikely, although not impossible, that this call outputs anything to stdout. Maybe you tried a different parameter order such as fwrite(temp, 1, sz, stdout) which attempts to output sz bytes from the contents of the FILE structure pointed to by temp to stdout and would show bizarre output if anything at all.

    • There might not be sz bytes accessible via the FILE pointer. As a matter of fact, FILE * are opaque pointers; the FILE type may be an incomplete type without an actual definition, so no actual bytes may be readable at that address. Reading bytes from stdout has undefined behavior.

    • Even sz = ftell(temp) does not produce a reliable result as the stream was opened in text mode. On Unix systems, this would evaluate to the file length in bytes, but on legacy systems with obscure text file handling, the result can only be passed to fseek() with SEEK_SET mode for later repositioning; its numerical value is meaningless.

    Here is a modified version:

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int concatenate(int argc, char *argv[]) {
        for (int i = 1; i < argc; i++) {
            FILE *temp;
            int c;
    
            if ((temp = fopen(argv[i], "r")) == NULL) {
                fprintf(stderr, "Error while opening file %s: %sn",
                        argv[i], strerror(errno));
                return EXIT_FAILURE;
            } 
    
            while ((c = getc(temp)) != EOF)
                putchar(c);
    
            fclose(temp);
        }
        return 0;
    }
    
    Login or Signup to reply.
  2. The problem is here:

            fwrite(stdout, 1, sz, temp);
    

    probably what you want is:

            printf("%un", sz);
    

    fwrite will print the binary representation of the data you pass to it (and you also pass it incorrectly, not as a pointer reference)

    That will print the files sizes to stdout which is what you apparently do in your code. Despite of the call being called concatenate() this is something strange and probably has directed other colleagues to show you how to concatenate files. You need to explain a bit more. Please, edit your question to clarify.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search