指向另一个结构的指针,写入并从文件中读取给出SegFault [英] pointer to one struct in another, writing and reading it from file gives SegFault

查看:173
本文介绍了指向另一个结构的指针,写入并从文件中读取给出SegFault的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习C语言的C技巧,目前我在第17次练习



我正在做Extra Credits部分。让数据库代码在该页上给出
我试图改变代码来接受MAX_DATA和MAX_ROWS的参数,将它们存储在数据库中结构,并写入到文件,从而创建一个可以任意大小的数据库

所以,我注释了#define指令,并改变了地址和数据库结构如下所示:

$ $ p $ $ $ $ c $ struct结构地址{
int id;
int set;
char * name;
char * email;
};

struct数据库{
int MAX_DATA;
int MAX_ROWS;
struct地址*行;
};这样,我就可以从用户那里得到MAX_DATA和MAX_ROWS参数来创建一个数据库,就像他自己的数据库一样喜好。我在代码中修改的其他东西是:
$ b $ p Database_create函数:

$ $ $ $ $ $ $ c $ void $ Database_create(struct Connection * conn,int MAX_DATA,int MAX_ROWS)
{
int i = 0;
conn-> db-> MAX_DATA = MAX_DATA;
conn-> db-> MAX_ROWS = MAX_ROWS;
conn-> db-> rows = malloc(sizeof(struct Address)* MAX_ROWS);
for(i = 0; i< MAX_ROWS; i ++){
struct Address addr = {.id = i,.set = 0};
conn-> db-> rows [i] = addr;


$ / code $ / pre

字节,SegFault是:
$ b $ pre $ void $ Database_set(struct Connection * conn,int id,const char * name,const char * email)
{
struct Address * addr =& conn-> db-> rows [id];
int MAX_DATA = conn-> db-> MAX_DATA;
if(addr-> set)die(已经设置,先删除);
/ *这个if语句给addr-> set * /
addr-> set = 1;
addr-> name = malloc(sizeof(char)* MAX_DATA);
addr-> email = malloc(sizeof(char)* MAX_DATA);
//警告:错误,阅读如何打破它并修复这个
char * res = strncpy(addr-> name,name,MAX_DATA);
//演示strncpy bug
if(!res)die(Name copy failed);

res = strncpy(addr-> email,email,MAX_DATA);
if(!res)die(Email copy failed);
}

我知道这个代码片段不是整个部分,在这里粘贴整个代码。
所以,我已经发布在这里: http://pastebin.com/EbKShT3r
我可以使用'c'选项创建和编写首次运行的数据库。但是,要使用's'选项添加条目,会发生分段错误。

编辑
最后,我得到这个程序使用@WhizCraig给出的解决方案
,为了释放内存,这里是我正在尝试:

$ pre $ void $ Database_close(struct Connection * conn)
{
int i;
if(conn){
int MAX_ROWS = conn-> db-> MAX_ROWS;
for(i = 0; i< MAX_ROWS; i ++){
struct address * row = conn-> db-> rows + i;
if(row-> set){
free(row-> name);
free(row-> email);


free(conn-> db-> rows);
if(conn-> file)fclose(conn-> file);
if(conn-> db)free(conn-> db);
free(conn);




$ b $ p
$ b我的错误Valgrind,是泄漏。我不明白上面的代码中的错误。
然而,主要的问题似乎已经解决了:)

解决方案

  struct地址{
int id;
int set;
char * name;
char * email;
};

struct数据库{
int MAX_DATA;
int MAX_ROWS;
地址**行; //使用指针阵列
};

void Database_create(Connection * conn,int MAX_DATA,int MAX_ROWS)
{
int i = 0;
conn-> db-> MAX_DATA = MAX_DATA;
conn-> db-> MAX_ROWS = MAX_ROWS;
conn-> db-> rows =(Address **)malloc(sizeof(Address *)* MAX_ROWS); (i = 0; i< MAX_ROWS; i ++){
conn-> db-> rows [i] =(Address *)malloc(sizeof(Address))

;
conn-> db-> rows [i] - > id = i;
conn-> db-> rows [i] - > set = 0;


$ b void Database_set(Connection * conn,int id,const char * name,const char * email)
{
if(! (conn& conn-> db& conn-> db-> rows& conn-> db-> rows [id]))return;

地址* addr = conn-> db-> rows [id];
int MAX_DATA = conn-> db-> MAX_DATA;

if(addr-> set == 0)die(已经设置,先删除);

addr-> set = 1;
addr-> name = malloc(sizeof(char)* MAX_DATA);
addr-> email = malloc(sizeof(char)* MAX_DATA);
$ b $ char * res = strncpy(addr-> name,name,MAX_DATA);
if(!res)die(Name copy failed);

res = strncpy(addr-> email,email,MAX_DATA);
if(!res)die(Email copy failed);
}

void Database_close(Connection * conn)
{
size_t i;如果(conn){
if(con> db& conn-> db-> rows){
for(i = 0; i< conn- > db-> MAX_ROWS; i ++){

Address * cur = conn-> db-> rows [i];
free(cur);



$ b if(conn-> file)fclose(conn-> file);
if(conn-> db)free(conn-> db);
free(conn);
}
}


I am brushing up my C skills from Learn C The Hard Way, currently I am at 17th Exercise.

I am doing the 'Extra Credits' part. Making the database code given on that page to get I am trying to

"Change the code to accept parameters for MAX_DATA and MAX_ROWS, store them in the Database struct, and write that to the file, thus creating a database that can be arbitrarily sized"

So, I commented out the #define directives, and changed Address and Database structs as given:

struct Address {
    int id;
    int set;
    char *name;
    char *email;
};

struct Database {
    int MAX_DATA;
    int MAX_ROWS;
    struct Address *rows;
};

So that, I can get MAX_DATA, and MAX_ROWS parameters from the user to create a database as per his liking. Other things I changed in the code are --

The Database_create function :

void Database_create(struct Connection *conn, int MAX_DATA, int MAX_ROWS)
{
        int i = 0;
        conn->db->MAX_DATA = MAX_DATA;
        conn->db->MAX_ROWS = MAX_ROWS;
        conn->db->rows = malloc(sizeof(struct Address) * MAX_ROWS);
        for(i = 0; i < MAX_ROWS; i++) {
                struct Address addr = {.id = i, .set = 0};
                conn->db->rows[i] = addr;
        }
}

The part where I am getting 'Invalid read of 4 bytes', and SegFault is :

void Database_set(struct Connection *conn, int id, const char *name, const char *email)
{
    struct Address *addr = &conn->db->rows[id];
    int MAX_DATA = conn->db->MAX_DATA;
    if(addr->set) die("Already set, delete it first");
    /* This if statement gives error for addr->set */
    addr->set = 1;
    addr->name = malloc(sizeof(char) * MAX_DATA);
    addr->email = malloc(sizeof(char) * MAX_DATA);
    // WARNING: bug, read the "How To Break It" and fix this
    char *res = strncpy(addr->name, name, MAX_DATA);
    // demonstrate the strncpy bug
    if(!res) die("Name copy failed");

    res = strncpy(addr->email, email, MAX_DATA);
    if(!res) die("Email copy failed");
}

I know this code snippets isn't the whole part, but I can't paste the whole code here. So, I've posted it here : http://pastebin.com/EbKShT3r I can create and write database for the first run using 'c' option. However, to add entries using 's' option, the Segmentation Fault occurs.

EDIT : So, Finally, I got this program working with the solution given under by @WhizCraig However, for freeing the memory, here is what I am trying :

void Database_close(struct Connection *conn)
{
    int i;
    if (conn) {
        int MAX_ROWS = conn->db->MAX_ROWS;
        for (i=0; i<MAX_ROWS; i++) {
            struct Address *row = conn->db->rows+i;
            if (row->set) {
                free(row->name);
                free(row->email);
            }
        }
        free(conn->db->rows);
        if(conn->file) fclose(conn->file);
        if(conn->db) free(conn->db);
        free(conn);
    }
}

And, I am getting errors in Valgrind, memory is leaking. I don't understand the error in above code. However, the main problem appears to be solved :)

解决方案

struct Address {
    int id;
    int set;
    char *name;
    char *email;
};

struct Database {
    int MAX_DATA;
    int MAX_ROWS;
    Address **rows; // USE ARRAY OF POINTERS
};

void Database_create(Connection *conn, int MAX_DATA, int MAX_ROWS)
{
        int i = 0;
        conn->db->MAX_DATA = MAX_DATA;
        conn->db->MAX_ROWS = MAX_ROWS;
        conn->db->rows = (Address**)malloc(sizeof(Address*) * MAX_ROWS);

        for(i = 0; i < MAX_ROWS; i++) {
                conn->db->rows[i] = (Address*)malloc(sizeof(Address));
                conn->db->rows[i]->id = i;
                conn->db->rows[i]->set = 0;
        }
}

void Database_set(Connection *conn, int id, const char *name, const char *email)
{
    if (!(conn && conn->db && conn->db->rows && conn->db->rows[id])) return;

    Address *addr = conn->db->rows[id];
    int MAX_DATA = conn->db->MAX_DATA;

    if(addr->set == 0) die("Already set, delete it first");

    addr->set = 1;
    addr->name = malloc(sizeof(char) * MAX_DATA);
    addr->email = malloc(sizeof(char) * MAX_DATA);

    char *res = strncpy(addr->name, name, MAX_DATA);
    if(!res) die("Name copy failed");

    res = strncpy(addr->email, email, MAX_DATA);
    if(!res) die("Email copy failed");
}

void Database_close(Connection *conn)
{
        size_t i;
        if(conn) {
                if (con->db && conn->db->rows) {
                        for (i = 0; i < conn->db->MAX_ROWS; i++) {

                                Address *cur = conn->db->rows[i];
                                free(cur);

                        }
                }

                if(conn->file) fclose(conn->file);
                if(conn->db) free(conn->db);
                free(conn);
        }
}

这篇关于指向另一个结构的指针,写入并从文件中读取给出SegFault的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆