Home > Software design >  what is the difference between reading from a file to a location, then writing from that location to
what is the difference between reading from a file to a location, then writing from that location to

Time:01-05

I was solving volume (one of the questions in cs50x). Apparently the code that I wrote, works when the file contents are read in an array and from that array, written into the output file.

When I tried to read the input file contents to the output file, by giving a pointer to the output file, it didn't pop any error, but the output was not working.

Can someone explain how reading from a file to a location (say an array) and reading from one file into another file are different.

THIS IS THE CODE FOR REFERENCE

`// Modifies the volume of an audio file

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

// Number of bytes in .wav header
const int HEADER_SIZE = 44;

int main(int argc, char *argv[])
{
    // Check command-line arguments
    if (argc != 4)
    {
        printf("Usage: ./volume input.wav output.wav factor\n");
        return 1;
    }

    // Open files and determine scaling factor
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    float factor = atof(argv[3]);

    // TODO: Copy header from input file to output file

    uint8_t arr[HEADER_SIZE];

    fread(arr, sizeof(uint8_t), HEADER_SIZE, input);

    fwrite(arr, sizeof(uint8_t), HEADER_SIZE, output);

    // creating a temprary location in memory for the content bytes of a wave file

    int16_t buffer;

    // TODO: Read samples from input file and write updated data to output file

    while (fread(&buffer, sizeof(int16_t), 1, input))

    {

        buffer = (buffer) * factor;
        fwrite(&buffer, sizeof(int16_t), 1, output);
    }

    // Close files
    fclose(input);
    fclose(output);
}`

But if I wrote the code below, it won't work


   ` // TODO: Copy header from input file to output file

    // reading from the input file to the output file.

    fread(output, sizeof(uint8_t), HEADER_SIZE, input);

    // creating a temprary location in memory for the content bytes of a wave file

    int16_t buffer;

    // TODO: Read samples from input file and write updated data to output file

    while (fread(&buffer, sizeof(int16_t), 1, input))

    {
        buffer = (buffer) * factor;
        fwrite(&buffer, sizeof(int16_t), 1, output);
    }`

Can someone explain how reading from a file to a location (say an array) and reading from one file into another file are different.

CodePudding user response:

In your second sample code you do a file read from input to output. In this specific case, output is considered as a void * buffer to store data ; not as a file handle to write data to.

fread(output, sizeof(uint8_t), HEADER_SIZE, input);

You should rather consider something like this:

uint8_t buffer[HEADER_SIZE];
size_t read, written;

read = fread(buffer, 1, HEADER_SIZE, input);
written = fwrite(buffer, 1, read, output);

NOTE: for simplicity I do not check return values here, I leave it up to the OP.

EDIT:

1 - What is FILE pointer?

A FILE * is a pointer to a dynamically allocated FILE structure. This structure holds specific pieces of information used by the API to determine which file is concerned by read, write, seek, etc.

2 - Why doesn't writing to file handle works?

The fread function takes a pointer as first parameter. A FILE * is a pointer indeed. However, fread expects a memory region to write data to.

Passing a FILE * will be accepted by the compiler since every pointers cast okay to void *.

However, during runtime, the passed FILE * pointer will be used for storing read data bytes as a memory buffer. This means that fread will override the target memory structure with read content starting from the pointed address.

In the end, the FILE * structure will no longer hold the API data and thus, when the user will use the FILE * pointer for writing data to a file, the original FILE * being corrupted, fwrite will most likely lead to a segfault.

CodePudding user response:

See this answer to understand what FILE* entails and why passing a pointer to a different type doesn't work as expected. More detail on the FILE structure here.

CodePudding user response:

From the man page:

The function fread() reads nmemb items of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.

Signature:

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

The first argument of fread is a void pointer that is to be written to. You passed it a FILE * in your code.

// reading from the input file to the output file.

fread(output, sizeof(uint8_t), HEADER_SIZE, input);

On a Unix-based system, you could map the file into memory with mmap and then work with it. Or just read the file into a buffer similar to how you did in your first example.

FILE is a structure defined in the standard library. It contains all the relevant information about the opened file.

From C11:

(...) FILE which is an object type capable of recording all the information needed to control a stream, including its file position indicator, a pointer to its associated buffer (if any), an error indicator that records whether a read/write error has occurred, and an end-of-file indicator that records whether the end of the file has been reached; (...)

fopen returns a pointer to a FILE structure. The pointer itself is not pointing to the memory in the file, it's pointing to a structure of type FILE.

The contents of that structure are completely implementation defined.

Here's what FILE entails on my system:

type = struct _IO_FILE {
    int _flags;
    char *_IO_read_ptr;
    char *_IO_read_end;
    char *_IO_read_base;
    char *_IO_write_base;
    char *_IO_write_ptr;
    char *_IO_write_end;
    char *_IO_buf_base;
    char *_IO_buf_end;
    char *_IO_save_base;
    char *_IO_backup_base;
    char *_IO_save_end;
    struct _IO_marker *_markers;
    struct _IO_FILE *_chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset;
    unsigned short _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t *_lock;
    __off64_t _offset;
    struct _IO_codecvt *_codecvt;
    struct _IO_wide_data *_wide_data;
    struct _IO_FILE *_freeres_list;
    void *_freeres_buf;
    size_t __pad5;
    int _mode;
    char _unused2[20];
} *
  • Related