1

So, for some reason, I need to make a external file (.DAT) to store data by appending the new one to the end of old data.

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

int main () {
    typedef struct {
        char *Name;
        int Index;
    } DataFile;

    static FILE *file;
    size_t result;
    DataFile *DataTable;

    file = fopen("database.DAT","ab");
    DataTable = (DataFile *) malloc (sizeof(DataFile));
    DataTable[0].Name = "somefile.txt";
    DataTable[0].Index = 7;
    printf("%s %d \n",DataTable[0].Name,DataTable[0].Index);
    result = fwrite(DataTable,sizeof(DataFile),1,file);
    fclose(file);
    free(DataTable);
    return 0;
}

After running code above, I then check if the data stored correctly. So, I make this code below.

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

int main () {
    typedef struct {
        char *Name;
        int Index;
    } DataFile;

    static FILE *file;
    size_t result;
    long size;
    int i;
    DataFile *DataTable;

    file = fopen("database.DAT","rb");
    if (file == NULL) printf("Error1");

    // Determine the size of file
    fseek(file,0,SEEK_END);
    size = ftell(file);
    rewind(file);

    DataTable = (DataFile *) malloc ((size/sizeof(DataFile)) * sizeof(DataFile));
    if (DataTable == NULL) printf("Error2");

    result = fread(DataTable,sizeof(DataFile),size/sizeof(DataFile),file);
    fclose(file);

    for (i=0; i<result; i++) {
        printf("%s %d \n",DataTable[i].Name,DataTable[i].Index);
    }
    free(DataTable);
    return 0;
}

However, it gives output

somefile.txt 7

from the first code block and

Error1 7

from the second code block. I notice that the problem is not because the failure either when opening .DAT file or when allocating memory for DataTable. Also, it works for int type (Index) but not for char* type (Name) when reading from .DAT file. I have no idea what to do to solve this char*-type-reading problem (and where 'error1' comes from). (not even google gives me answer.)

  • As usual, `DataTable = (DataFile *) malloc (sizeof(DataFile));` is better written as `DataTable = malloc(sizeof *DataTable);`. [Dont't cast the return value of `malloc()` in C](http://stackoverflow.com/a/605858/28169), and don't repeat yourself needlessly. – unwind Nov 15 '12 at 08:11

3 Answers3

2

Your structure DataFile stores one pointer and one integer. When you write it to the file, you write some program specific pointer to a string, and an integer.

When reading from it, you just refill your structure with the pointer and the integer, wich means that DataFile.Name will be a pointer to a probably-not-initialized memory segment. But since you created your file pointing to the first hard-coded string ("filename.txt"), some undefined but understandable behaviour happens, and your pointer in this case points to the first hard-coded string you wrote in you second program (which in your case is Error1)

What you really want to do is write the real string in your file.

A simple solution, if you want to the keep the hole writing structure thing is to create an array instead of a pointer

typedef struct {
        char Name[512];
        int Index;
    } DataFile;

then initialize your data with

strncpy(DataTable[0].Name, "somefile.txt", sizeof(DataTable[0].Name) - 1); // just to make sure you dont overflow your array size
DataTable[0].Name[sizeof(DataTable[0].Name) - 1] = '\0';

and retreview your data the way you did.

tomahh
  • 13,441
  • 3
  • 49
  • 70
1

A char* is only a pointer, i.e. the address of the character array containing your strings. You don't write the strings themselves to the file. After reading the file, as the same strings aren't in your memory at the same addresses any more, the application will fail.

You'll have to come up with a way to save the strings themselves to file as well. Probably by first writing their length, and then writing their content. Upon reading, you can use the length information to allocate memory dynamically, then read into that memory.

MvG
  • 57,380
  • 22
  • 148
  • 276
0

In your writing code you haven't allocated storage for char *Name. When you perform the DataTable[0].Name = "somefile.txt" instruction you're not actually copying the "somefile.txt" into memory pointed by Name, it's actually assigning a Name a value pointing to a constant characters string (moreover, it will become dangling pointer since the string is an rvalue, i.e. doesn't have a memory to be addressed via). Same goes for your file reading code. You need to:

  1. Allocate storage for your Name.
  2. Copy the string using memcpy or similar into the allocated storage.
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85