简体   繁体   中英

Reading a certain position in a binary file using structs with pointers

I am storing in a binary file a struct like this:

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

That holds an array of structs of this type:

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

I want to create and store in a binary file various users, and each time i do that i store their position in the file in a hashtable for later being able to seek them using fseek(), here is the aspect of an item in the hashtable:

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

i tried to implement the ideia above and create two users and later try to fetch them, but i can only get one, since the other breaks the program.

#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;
}

the program fails with this kind of input:

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

Why is the program above finding one of the users and not the other?

Note: i know this would be better to do with normal .txt files but i want to use the speed of the fseek() function to get the users in the file

You cannot call fseek(p, pos* sizeof(user), SEEK_SET); to skip to pos user in your file. sizeof(user) returns size in bytes of user struct but you have pointer following in this struct, which points to array filled by your following objects. If you want to skip to pos user you should have information how many following objects are in each user. You don't have this information so you can read your file user one by one to reach pos user.

// 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
}

I see three problems in the get_user_info function.

  1. The offset calculation doesn't include the following structures. The file contains a user structure with some number of following structures, and then the next user structure. So there's no way to compute the offset without reading every user structure to get the n_following member.

  2. The code only malloc s space for one following struct, but then reads 2 structures into that memory. The amount of memory should be sizeof(following) * print_user->n_following

  3. The fread is using a hard-code 2 instead of n_following when reading the following structures.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM