使用结构中的指针从文件中读取

时间:2013-12-30 17:46:22

标签: c pointers

我试着用带有结构指针的文件来编写和读取。但是当我从文件中读到时,我看到了一些垃圾值。我在Linux上使用GCC 4.7.2。需要一些帮助。

读:

//read from a file

#include<stdio.h>

typedef struct 
{
    char* name;
    char* phone;
}LISTING;

int main(void)
{
    LISTING phoneList[14];  
    FILE * fp = NULL;

    fp = fopen("/media/Study/PhoneDirectory.dat","rb"); 

    if(fp == NULL)
        printf("Error opening file!!!");    

    fseek(fp,0,SEEK_SET);

    if(fread(&phoneList[1],sizeof(LISTING),1,fp)==1)
        printf("%s %s",phoneList[1].name,phoneList[1].phone);

    fclose(fp);

    return 0;
}

写下:

//Write to file

#include<stdio.h>

typedef struct 
{
    char* name;
    char* phone;
}LISTING;

int main(void)
{
    LISTING phoneList[2];   
    FILE * fp = NULL;

    fp = fopen("/media/Study/PhoneDirectory.dat","wb");

    phoneList[1].name = "Santosh";
    phoneList[1].phone = "9657681798";

    if(fwrite(&phoneList[1],sizeof(LISTING),1,fp)==1)
        printf("inserted");

    fclose(fp);

    return 0;
}

3 个答案:

答案 0 :(得分:1)

指针仅在它们源自的应用程序过程中有意义。如果你将它们写入文件,正如你在这里所做的那样,你读回的值将毫无意义 - 它们很可能指向未初始化的内存,或者指向完全用于其他内存的内存。

您需要提出另一种将此数据写入文件的方法。

答案 1 :(得分:0)

你遇到的问题是char *和char []之间的区别。您当然可以将字符串文字分配给char *,但是您需要了解LISTING结构的内容,以及您希望如何将数据序列化和反序列化为文件。

保存来自一个进程的指针并将它们读入另一个进程是没有意义的,因此您可能希望保存内容(指针指向的位置)。您希望将两个值(名称,电话)存储到文件中。由于您可能希望存储文字名称和文字电话,因此我们请考虑文件的外观:

roast duck|212-333-4444
peking duck|411-511-61111
duck soup|314-222-3333
free duck|800-111-2222
...

您需要使用函数来序列化和反序列化数据。由于您的LISTING类型是指针,因此您需要在读取这些值时为这些值分配适当的空间,并且需要函数(方法)从文件中读取序列化数据并将序列化数据写入文件。

阅读(你需要分配足够的空间),

int
listing_read(FILE*fp, LISTING* listing)
{
    char name_buffer[100];
    char phone_buffer[100];

    if(!fp) return(-1);
    if(!listing) return(-2);

    int res = fscanf(fp,"%s|%s\n",name_buffer,phone_buffer);
    if( !res ) {
        //handle error here
    }
    //careful here, you cannot free if you didn't malloc/strdup
    if(listing->name) free(listing->name);
    if(listing->phone) free(listing->phone);

    listing->name = strdup(name_buffer);
    listing->phone = strdup(phone_buffer);
    return(0);
}

写作(您需要提供正确的格式),

int
listing_write(FILE*fp, LISTING* listing)
{
    if(!fp) return(-1);
    if(!listing) return(-2);

    fprintf(fp,"%s|%s\n",listing->name,listing->phone);
    return(0);
}

以下是修改代码的方法,

//read from a file
#include<stdio.h>

typedef struct 
{
char* name;
char* phone;
}LISTING;

int main(void)
{
    LISTING phoneList[14];  
    FILE* fp = NULL;
    if( !(fp = fopen("/media/Study/PhoneDirectory.dat","rb")) ) {
        printf("Error opening file!!!");
        exit(1);
    }

    fseek(fp,0,SEEK_SET);
    if( listing_read(fp,&phoneList[0]) >= 0 ) {
        printf("%s %s",phoneList[0].name,phoneList[0].phone);
    }
    fclose(fp);

    return 0;
}

以下是编写文件的方式会发生变化,

//Write to file
#include<stdio.h>

typedef struct 
{
char* name;
char* phone;
}LISTING;

int main(void)
{
    LISTING phoneList[14];   
    FILE* fp = NULL;

    if( !(fp = fopen("/media/Study/PhoneDirectory.dat","wb")) ) {
        printf("error, cannot write file\n");
        exit(1);
    }

    phoneList[0].name = "Santosh";
    phoneList[0].phone = "9657681798";

    if( listing_write(fp,&phoneList[0])>=0) {
        printf("inserted");
    }
    fclose(fp);

    return 0;
}

请注意,在编写程序时,您将字符串文字“Santosh”和“9657681798”分配给LISTING成员名称和电话。虽然合法,但您需要更好地了解C在这里所做的事情。 C获取这些C字符串常量的地址,并将这些地址分配给phonelist [1] .name和phonelist [1] .phone成员指针。

考虑一下,如果你做了这个任务,

    phoneList[0].name = "Santosh";
    phoneList[0].phone = "9657681798";

您已将指向常量字符串的指针分配给结构成员。

但是如果你要分配空间(例如,使用strdup()),

    phoneList[0].name = strdup("Santosh");
    phoneList[0].phone = strdup("9657681798");

您已为字符串分配空间,为这些成员元素指定独立位置。哪个更有可能是你想要做的。


请注意,我使用了phonelist [0],因为C具有从零开始的数组。

答案 2 :(得分:-1)

printf("%s %s",phoneList[1].name,phoneList[1].phone);

上述语句调用未定义的行为。

指针name&amp;结构对象phone的{​​{1}}未初始化,取消引用它们调用UB。在你的情况下,他们扔掉了垃圾值,但也可能导致崩溃。

为了适合您阅读文件内容并将其存储在struct对象中的情况,请使用phoneList[1]函数逐行读取它们(假设所有细节都按行存储)然后动态分配getline指针的内存然后将它们分配给读取值。但是,这种方法导致大量内存管理容易出错。