Чтение определенной позиции в двоичном файле с использованием структур с указателями - PullRequest
0 голосов
/ 10 июня 2018

Я храню в двоичном файле структуру, подобную этой:

typedef struct user {
    char nick[6];
    int n_following;
    following *following;
}user;

, которая содержит массив структур этого типа:

typedef struct following{
    char nick[6];
    int last_message;
}following;

Я хочу создать и сохранить вбинарный файл различных пользователей, и каждый раз, когда я делаю это, я сохраняю их позицию в файле в хеш-таблице для последующей возможности поиска их с помощью fseek (), вот аспект элемента в хеш-таблице:

typedef struct user_pos {
    char nick[6];
    int position_in_file;
}user_pos;

Я попытался реализовать описанные выше идеи и создать двух пользователей, а затем попытаться получить их, но я могу получить только одного, так как другой нарушает работу программы.

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

typedef struct following{
    char nick[6];
    int last_message;
}following;

typedef struct user {
    char nick[6];
    int n_following;
    following *following;
}user;    

void insert_user(char *input_a, int n){

    FILE *p;
    p=fopen("users","ab");
    user *new_user = malloc(sizeof(user));
    strcpy(new_user->nick, input_a);
    new_user->n_following = n;
    new_user->following = malloc(sizeof(following) * new_user->n_following);
    strcpy(new_user->following[0].nick, "la");
    new_user->following[0].last_message = 0;
    strcpy(new_user->following[1].nick, "zz");
    new_user->following[1].last_message = 2;

    fwrite(&new_user->nick, sizeof(new_user->nick), 1, p);
    fwrite(&new_user->n_following, sizeof(new_user->n_following), 1, p);
    fwrite(new_user->following, sizeof(following), new_user->n_following, p);
    printf("user created\n");
    fclose(p);
}

void get_user_info(char *input_a, int pos){


    FILE *p;
    p=fopen("users","rb");
    user *print_user = malloc(sizeof(user));

    fseek(p, pos* sizeof(user), SEEK_SET);

    fread(&print_user->nick, sizeof(print_user->nick), 1, p);
    fread(&print_user->n_following, sizeof(print_user->n_following), 1, p);
    print_user->following = malloc(sizeof(following));
    fread(print_user->following, sizeof(following), 2, p);

    printf("nick: %s, following: %d\n", print_user->nick, print_user->n_following);
    for(int i = 0; i < print_user->n_following; i++){
        printf("nick: %s, last_read: %d\n", print_user->following[i].nick, print_user->following[i].last_message);
    }

    fclose(p);
}

int main(){
    //hashtable *active_users = create();
    char buffer[38];
    char tipo;
    int n;
    char input_a[6];
    while(fgets(buffer, 38, stdin)){
        sscanf(buffer, "%c %s %d", &tipo, input_a, &n);
        switch(tipo) {
            case 'U' :
                insert_user(input_a, n);
                break;
            case 'S' :
                get_user_info(input_a, n);
                break;
            case 'X' :
                exit(0);
            default :
                printf("Operacao invalida\n");
        }
    }
    return 0;
}

программа завершается с этимтип ввода:

input: U me 2
output: user created
input: U ro 2
output: user created
input: S me 0
output: nick: me, following: 2
        nick: la, last_read: 0
        nick: zz, last_read: 2
input: S ro 1//program breaks

Почему программа выше находит одного из пользователей, а не другого?

Примечание: я знаю, что это было бы лучше делать с обычными файлами .txt, ноя хочу использовать скорость функции fseek (), чтобы получить пользователей в файле

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

Я вижу три проблемы в функции get_user_info.

  1. Расчет смещения не включает структуры following.Файл содержит структуру user с некоторым количеством структур following, а затем следующую структуру user.Таким образом, нет способа вычислить смещение без чтения каждой пользовательской структуры, чтобы получить n_following член.

  2. Код только malloc с пробелом для одной following структуры, но затемчитает 2 структуры в эту память.Объем памяти должен составлять sizeof(following) * print_user->n_following

  3. При чтении следующих структур fread использует жесткий код 2 вместо n_following.

0 голосов
/ 10 июня 2018

Вы не можете позвонить fseek(p, pos* sizeof(user), SEEK_SET);, чтобы перейти к pos пользователю в вашем файле.sizeof(user) возвращает размер в байтах структуры user, но в этой структуре есть указатель following, который указывает на массив, заполненный вашими following объектами.Если вы хотите перейти к пользователю pos, у вас должна быть информация о количестве следующих объектов у каждого пользователя.У вас нет этой информации, поэтому вы можете прочитать файл пользователя один за другим, чтобы достичь pos пользователя.

// pseudocode 
get_user_info (int pos) {
   while (pos--) {
      skip 6 bytes // nick
      read 4 bytes n_following;
      skip n_following * sizeof(following) bytes
   }
   // here you can read data of pos user
}
...