cmemorymallocallocation

Unable to access dynamically allocated struct char pointer in C


Unfortunately problem looks for me to be quite complex.

I'm having set of structs and function. Pardon me for terrible naming.

hashmap.h

#ifndef HASHMAP_H
#define HASHMAP_H

typedef struct HashMapNode HashMapNode;

struct HashMapNode {
  char *key;
  int  value;
  HashMapNode *collision;
};

typedef struct {
  int size;
  HashMapNode **map;
} HashMap;

HashMap *hashmap_new(size_t size);
HashMapNode *hashmap_node_new(HashMapNode *node);

#endif

hashmap.c

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

HashMapNode *hashmap_node_new(HashMapNode *node){
  
  node = malloc(sizeof(HashMapNode));

  node->key       = NULL;
  node->value     = 0;
  node->collision = NULL;

  return node;

};

HashMap *hashmap_new(size_t size){

  HashMap *hash_map = malloc(sizeof(HashMap));

  hash_map->size = size;
  hash_map->map  = malloc(sizeof(HashMapNode*) * size);

  HashMapNode *node;

  for (int i = 0; i < hash_map->size; i++){  
    node = hashmap_node_new(hash_map->map[i]);
    printf("Node pointer: %p, key pointer: %p, collision pointer %p\n", node, node->key, node->collision);
  };

  return hash_map;

};

Here is program workflow and error.

main.c

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

int main(){

  HashMap *hash_map = hashmap_new(100);
  
  printf("%p\n", hash_map->map[4]->key);

  return 0;
};

Output:

...
Node pointer: 0x5607cb89b8b0, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b8d0, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b8f0, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b910, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b930, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b950, key pointer: (nil), collision pointer (nil)
Node pointer: 0x5607cb89b970, key pointer: (nil), collision pointer (nil)
Segmentation fault (core dumped)

Program fails at:

(Important fact is that it fails to print pointer for index > 3)

Program received signal SIGSEGV, Segmentation fault.
main () at usage.c:18
18        printf("%p\n", hash_map->map[4]->key);

GDB debug:

(gdb) print hash_map
$11 = (HashMap *) 0x5555555594a0
(gdb) print hash_map->map[0]->key
$12 = 0x7ffff7fa82f0 <main_arena+1648> "\340\202\372\367\377\177"
(gdb) print hash_map->map[1]->key
$13 = 0x7ffff7fa82f0 <main_arena+1648> "\340\202\372\367\377\177"
(gdb) print hash_map->map[2]->key
$14 = 0x0
(gdb) print hash_map->map[3]->key
$15 = 0x0
(gdb) print hash_map->map[4]->key
Cannot access memory at address 0x61590a616963616d

Not really sure where am I making a mistake..


Solution

  • The function hashmap_node_new creates a new node and returns it, but it doesn't modify the original pointer that was passed in to the function by its argument.

    That means that the statement

    node = hashmap_node_new(hash_map->map[i]):
    

    will not modify hash_map->map[i]. You need to assign the pointer the function returns back to hash_map->map[i]:

    node = hashmap_node_new(hash_map->map[i]):
    hash_map->map[i] = node;
    

    The reason that the hashmap_node_new doesn't modify the original pointer you pass in as the argument is because arguments in C are passed by value. That means the original value is copied, and the function only works on the copy not the original.

    This is basically the same as something like:

    int set_int(int value)
    {
        value = 5;
        return value;
    }
    
    // ...
    
    int my_value;
    int new_value;
    
    new_value = set_int(my_value);
    

    And expecting my_value to become initialized.