Search code examples
c++dynamic-memory-allocationbinaryfiles

Reading an array of chars from a binary file into another array of chars dynamically allocated in C++


I have a homework and I have to write an object into a binary file. Then I have to read that object from the binary file. Everything works fine,except a variable of type char*. I read it, but at the end of the text i got some random characters. I think the problem is the string terminator /0 ,but i don't know how to handle it. Can someone help me?

This is the code I used to write in the file:

        size_t n = strlen(input);// input is declared as char* input
        f.write((char*)&n, sizeof(n+1));
        f.write(input, n);

And this is how I tried to read this variable from the binary file:

        size_t n;
        f.read((char*)&n, sizeof(n));
        delete[] buffer;// buffer is also a char*
        buffer = new char[n];
        f.read(buffer, n);

I got the text from variable input, but at the end i got some random characters


Solution

  • C-strings must be nul-terminated

    C-strings have length elements plus a terminating nul character. You do in fact write the nul to file, but you fail to allocate space for and read it from file. Make sure things match.

    size_t n;
    f.read( (char *)&n, sizeof n );
    char * s = new char[n+1];
    f.read( s, n+1 );
    

    UPDATE: You have changed your code (as per commentary below) to not write the nul-terminator to file. Make sure to initialize it as such when you read it:

    ...
    char * buffer = new char[n+1];
    f.read( buffer, n );
    buffer[n] = '\0';
    

    Endianness nonsense you can totally ignore

    As an aside, you are not considering endianness issues with your size_t. I would personally make functions specifically for reading and writing integers in a file-specific endianness.

    size_t n = read_integer( f, 4 );
    char * s = new char[n+1];
    f.read( s, n+1 );
    

    Supposing a little-endian file, we could have:

    size_t read_integer( std::istream & f, int n )
    {
      size_t result = 0;
      while (n--)
        result = (result << 8) | ((unsigned char)f.get() & 0xFF);
      return result;
    }
    

    A corresponding function to write a little-endian value:

    std::ostream & write_integer( std::ostream & f, size_t n, size_t value )
    {
      while (n--)
      {
        f.put( value & 0xFF );
        value >>= 8;
      }
      return f;
    }
    

    (Untested. I might have goofed something.)

    Oh, also:

    write_integer( f, 4, strlen(s) );
    f.write( s, strlen(s)+1 );