3

http://c.learncodethehardway.org/を使用してCを学習しようとしていますが、第18章(http://c.learncodethehardway.org/book/learn-c- the-hard-waych18.html)そして私は誰かが私を助けてくれることを望んでいます。

私が抱えている特定の問題は、次のように定義された構造体がいくつかあることです。

#define MAX_ROWS = 500;
#define MAX_DATA = 512;

struct Address {
    int id;
    int set;
    char name[MAX_DATA];
    char email[MAX_DATA];
};

struct Database {
    struct Address rows[MAX_ROWS];       
};     

struct Connection {
    FILE *file;
    struct Database *db;
}; 

rows課題は、その定数に依存しない可変サイズを持つことができるようにそれを作り直すことです。

rowsしたがって、Database_createメソッドでは、次のように初期化しようとしています。

conn->db->rows = (struct Address*) malloc(max_rows * sizeof(struct Address));

ここでconn->db、データベースのインスタンスを指しmax_rows、関数に渡されるintです。また、データベース構造体を次のように変更しました

struct Database{
    struct Address* rows;
}

そのコードは問題なく動作しているように見えますが、メンバーのいずれかにアクセスしようとするとrows、使用されていないメモリのビットにアクセスしようとしていることを意味すると思われるセグメンテーション違反が発生します。

私はこれにかなりの時間を費やしました、そして私はあまり遠くに行くことができないと確信しています、しかし私は私を正しい軌道に乗せるためのどんなガイダンスにも本当に感謝します。


編集:Valgrindで実行した後、これにもう少し詳細を追加したかっただけで、エラーが発生します:

==11972== Invalid read of size 4
==11972==    at 0x100001578: Database_set (ex18.c:107)
==11972==    by 0x100001A2F: main (ex18.c:175)
==11972==  Address 0x7febac00140c is not stack'd, malloc'd or (recently) free'd

それが指すコード行は次のとおりです。

struct Address *addr = &conn->db->rows[id];
if(addr->set) die("Already set, delete it first");   

107行目は、if(addr->set)読めないものを読み込もうとしていることを意味していると思います。

4

3 に答える 3

2

あなたはしたくsizeof(struct Address)ないsizeof(struct Address*)

sizeof(struct Address*)は4のサイズを返す可能性があります(ただし、ターゲットプラットフォームに完全に依存します)が、Address構造体の実際のサイズは1040に近いです(charあたり1バイトおよびintあたり4を想定)

于 2012-06-22T13:04:50.413 に答える
1

編集:まあ、それは(あなたの最新の編集で)、あなたは実際にこの部分を適切にやっているように見えます。

実際には、アドレス構造に十分なサイズを割り当てていません。必要なものは次のようなものです。

struct Database{
    struct Address** rows;
}
//create array of pointers to Address structures
// (each element has size of the pointer)
conn->db->rows = (struct Address**) malloc(max_rows * sizeof(struct Address*));
for(int i=0; i < max_rows; i++) {
    conn->db->rows[i] = (struct Address*) malloc(sizeof(struct Address));
}

またはこれ:

struct Database{
    struct Address* rows;
}
//create array of Address structures
// (each element has size of the structure)
conn->db->rows = (struct Address*) malloc(max_rows * sizeof(struct Address));
于 2012-06-22T13:19:30.167 に答える
1

あなたがロードしているとき

void Database_load(struct Connection *conn)
{
        int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
        if(rc != 1) die("Failed to load database");
}

またはデータベースの作成、

void Database_write(struct Connection *conn)
{
        rewind(conn->file);

        int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
        if(rc != 1) die("Failed to write database");

        rc = fflush(conn->file);
        if(rc == -1) die("Cannot flush database.");
}

コンテンツ(es)を読み書きするのではなくstruct Address、メモリ位置へのポインタのみを読み取ります。以前に作成されたデータベースを読み取る場合、そのポインターは特定のものを指していません。これはワイルドポインターです。その後、もちろん、逆参照しようとすると、セグメンテーション違反が発生する可能性が非常に高くなります。逆参照しない場合は、意味のない疑似データが取得されます。

を変更する場合struct Databaserowsstruct Address*アイテムの数を保持し、で指定されたデータも処理するように読み取りおよび書き込みコードを変更する必要がありますrows。最初に持っているアイテムの数を書き、次に残り(max_datamax_rowsおよびアイテム)を書きます。読むときは、持っているアイテムの数を読み、それらにスペースを割り当て、アイテムを読んでmax_dataくださいmax_rows

于 2012-06-22T16:16:17.703 に答える