简体   繁体   中英

Why does malloc/calloc fail to allocate memory to certain members in an array of structures?

I want some function ( save() ) to get a pointer to array of structures dbEntry and fill it with data. This is where memory management issues come in.

This is my code:

Structure itself:

typedef struct dbEntry {
          unsigned int id;
          char* type;
          char* name;
          unsigned int parent_id;
          unsigned char* md5;
} dbEntry;

Memory allocation and calling save() :

int main(int argc, char const* argv[]){
          if (argc != 5) arg_error();

          if (strcmp(argv[1], "-s") == 0){
              FILE* database = fopen(argv[2], "wb");
              if (database == NULL) file_error();
              dbEntry* entries = malloc(150*sizeof(dbEntry*));
              for (int i=0; i<150; i++){
                  entries[i].id = 0;
                  entries[i].parent_id = 0;
                  entries[i].name = malloc(50*sizeof(char));
                  entries[i].type = malloc(10*sizeof(char));
                  entries[i].md5 = malloc(MD5_DIGEST_LENGTH*sizeof(unsigned char));
              }
              int entry_num = save(argv[4], 0, &entries);

save()

int save(char* dir_path, unsigned int parent, dbEntry** entries) {
          size_t path_len = strlen(dir_path);
          if (dir_path[path_len - 1] != '/') strcat(dir_path, "/");
          char dp_copy[path_len];
          strcpy(dp_copy, dir_path);
          DIR* dir = opendir(dir_path);
          struct dirent* dirent = readdir(dir);
          dirent = readdir(dir);
          dirent = readdir(dir);
          unsigned int id = 0;
          char* fpath;

          if (dirent == NULL) {
                  fprintf(stderr,
                          "Directory %s doesn't exist or can't be "
                          "opened. Check permissions\n",
                          dir_path);
                  exit(-1);
          }

          while (dirent != NULL) {
                  entries[id]->id = id;
                  strcpy(entries[id]->name, dirent->d_name);
                  entries[id]->parent_id = parent;

                  if (dirent->d_type == 8) {
                          strcpy(entries[id]->type, "file");
                          size_t len = strlen(dir_path)+strlen(dirent->d_name);
                          fpath = malloc(len);
                          strcpy(fpath, dir_path);
                          strcat(fpath, dirent->d_name);
                          FILE* file = fopen(fpath, "rb");
                          if (file == NULL){
                                  printf("Could not open file %s for reading\n", fpath);
                                  exit(-1);
                          }
                          md5digest(file, entries[id]->md5);
                          fclose(file);
                          printf("Saved %s\n", strcat(dir_path, dirent->d_name));

GDB output:

57              while (dirent != NULL) {
(gdb) n
58                      entries[id]->id = id;
(gdb) n
59                      strcpy(entries[id]->name, dirent->d_name);
(gdb) n
60                      entries[id]->parent_id = parent;
(gdb) n
62                      if (dirent->d_type == 8) {
(gdb) n
63                              strcpy(entries[id]->type, "file");
(gdb) n
64                              size_t len = strlen(dir_path)+strlen(dirent->d_name);
(gdb) n
65                              fpath = malloc(len);
(gdb) n
66                              strcpy(fpath, dir_path);
(gdb) n
67                              strcat(fpath, dirent->d_name);
(gdb) p entries
$1 = (dbEntry **) 0x7ffffffee110
(gdb) p entries[0]
$2 = (dbEntry *) 0x8403490
(gdb) p entries[1]
$3 = (dbEntry *) 0x0
(gdb) p entries[2]
$4 = (dbEntry *) 0x8403260
(gdb) p entries[3]
$5 = (dbEntry *) 0xf625f4cc70b40b00
(gdb) p entries[4]
$6 = (dbEntry *) 0x7ffffffee220
(gdb) p entries[5]
$7 = (dbEntry *) 0x0
(gdb) p entries[6]
$8 = (dbEntry *) 0x8001890 <__libc_csu_init>
(gdb) p entries[7]
$9 = (dbEntry *) 0x7ffffeb51b97 <__libc_start_main+231>
(gdb) p entries[8]
$10 = (dbEntry *) 0x2000000000
(gdb) p entries[0]->name
$11 = 0x8403950 ".bash_history"
(gdb)

For some reason, it failed to allocate memory for entries[1] , entries[5] and some more, so the program returns Address boundary error when trying to reference entries[1] .

Tried almost everything, but the issue persists. Looking for your help.

You have two problems:

  1. With

    malloc(150*sizeof(dbEntry*))

    you allocate memory for 150 pointers to dbEntry structures, not the dbEntry structures themselves.

    I recommend that you get the size of the data to allocate from the variable itself, as in:

     dbEntry *entries = malloc(150 * sizeof *entries);
  2. In the save function the variable entries is essentially a pointer to an array of dbEntry structures . You treat it as an array of pointers to structures (a pointer to an array is not the same as an array of pointers). You need to dereference the pointer to get the original pointer, which can then be dereferenced like an array of structures:

     (*entries)[id].id = id;

    Or simply not pass it as a pointer to a pointer:

     // Note only one asterisk // v int save(char* dir_path, unsigned int parent, dbEntry* entries) {... entries[id].id = id; // Entries can be treated like a normal array of 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