I am new to C programming and I am trying to create a key value structure as in Perl Programming. I saw one solution like :-
struct key_value
{
int key;
char* value;
};
struct key_value kv;
kv.key = 1;
kv.value = "foo";
But I don't know how to access these values from this structure. Can someone enlight on this ?
Here is an example:
#include <stdio.h>
#include <stdlib.h>
struct key_value
{
int key;
char* value;
};
int main(void)
{
int number_of_keys = 2;
struct key_value *kv = malloc(sizeof(struct key_value) * number_of_keys);
if (kv == NULL) {
perror("Malloc");
exit(EXIT_FAILURE);
}
kv[0].key = 8;
kv[0].value = "Test 8 key!";
kv[1].key = 6;
kv[1].value = "Test 6 key!";
printf("Key = %d\nKey value = %s\n", kv[0].key, kv[0].value);
printf("Key = %d\nKey value = %s\n", kv[1].key, kv[1].value);
free(kv);
return 0;
}
What you are missing is a collection. Most languages have a data type called a dictionary or a map or an associative array or some variation thereof. C does not have a data structure of this type; in fact, the only collection type you have built in to C is the array. So, if you want something where you can supply a key and get the value, you have to roll your own or find one on the Internet. The latter is probably preferable because you are likely to make mistakes and produce a slow data structure if you roll your own (especially if you are a beginner).
To give you a flavour of what you'll end up with, here's a simple example:
You'll need something to represent the collection; call it a ListMap for now:
struct ListMap;
The above is called an incomplete type. For now, we are not concerned with what's in it. You can't do anything with it except pass pointers to instances around.
You need a function to insert items into your collection. Its prototype would look something like this:
bool listMapInsert(struct ListMap* collection, int key, const char* value);
// Returns true if insert is successful, false if the map is full in some way.
And you need a function to retrieve the value for any one key.
const char* listMapValueForKey(struct ListMap* collection, int key);
You also need a function to initialise the collection:
struct ListMap* newListMap();
and to throw it away:
void freeListMap(struct ListMap* listMap);
The hard bit is implementing how those functions do what they do. Anyway, here's how you would use them:
struct ListMap* myMap = newListMap();
listMapInsert(myMap, 1, "foo");
listMapInsert(myMap, 1729, "taxi");
listMapInsert(myMap, 28, "perfect");
char* value = listMapValueForKey(myMap, 28); // perfect
freeListMap(myMap);
Here's a simple implementation. This is just for illustration because I haven't tested it and searching for entries increases linearly with the number of entries (you can do much better than that with hash tables and other structures).
enum
{
listMapCapacity = 20
};
struct ListMap
{
struct key_value kvPairs[listMapCapacity];
size_t count;
};
struct ListMap* newListMap()
{
struct ListMap* ret = calloc(1, sizeof *ret);
ret->count = 0; // not strictly necessary because of calloc
return ret;
}
bool listMapInsert(struct ListMap* collection, int key, const char* value)
{
if (collection->count == listMapCapacity)
{
return false;
}
collection->kvPairs[count].key = key;
collection->kvPairs[count].value = strdup(value);
count++;
return true;
}
const char* listMapValueForKey(struct ListMap* collection, int key)
{
const char* ret = NULL;
for (size_t i = 0 ; i < collection->count && ret == NULL ; ++i)
{
if (collection->kvPairs[i].key == key)
{
ret = kvPairs[i].value;
}
}
return ret;
}
void freeListMap(struct ListMap* listMap)
{
if (listMap == NULL)
{
return;
}
for (size_t i = 0 ; i < listMap->count ; ++i)
{
free(listMap->kvPair[i].value);
}
free(listMap);
}
typedef struct key_value
{
int key;
char* value;
}List;
struct key_value k1;
struct key_value k2;
struct key_value k3;
k1.key = 1;
k1.value = "foo";
k2.key = 2;
k2.value = "sec";
k3.key = 3;
k3.value = "third";
You will need to create N times the struct and give them values the way you did the first one. Or create array with N structs and iterate assign it values with a loop.
Array:
List arr[29];
int i;
for(i = 0;i<=28;i++){
arr[i].key = i;
arr[i].value = "W/e it needs to be";
}
The functionality you are looking for needs your own implementation in C; e.g. an array of your struct-type.
Here is an example of how to read the value for a key, without knowing anything about at which array-index the key will be found.
I have the keys numbered backward in order to illustrate that.
Note that more sophisticated API definitions are needed for special cases such as non-existing key; I just blindly return the last entry to keep things easy here.
#include <stdio.h>
#define MAPSIZE 30
struct key_value
{
int key;
char* value;
};
struct key_value kvmap[MAPSIZE];
void initmap(void)
{
int i;
for(i=0; i<MAPSIZE; i++)
{
kvmap[i].key=MAPSIZE-i-1;
kvmap[i].value="unset";
}
kvmap[0].value="zero";
kvmap[1].value="one";
kvmap[2].value="two";
kvmap[3].value="three";
kvmap[4].value="four";
kvmap[5].value="five";
kvmap[6].value="six";
kvmap[7].value="seven";
kvmap[8].value="eight";
kvmap[24].value="find this"; // it has the key "5"
}
char* readmap(int key)
{
int i=0;
while ((i<MAPSIZE-1) && (kvmap[i].key!=key))
{ printf("Not in %d\n", i);
++i;}
// will return last entry if key is not present
return kvmap[i].value;
}
int main(void)
{
initmap();
printf("%s\n", readmap(5));
return 0;
}
"I have to store 30 key/value pair"
Create an array of struct e.g., key_value.
struct key_value
{
int key;
char* value;
};
struct key_value kv[30];
kv[0].key = 1;
kv[0].value = "foo";
printf("%s", kv[0].value);
You can loop through to assign values to keys and values.
Access to whatever is in kv is simple.
int i = kv[0].key`;// copy value of k[0].key to i
char *v = kv[0].value; // copy value of k[0].value to v;
Your code already have the method to acess the values.
kv.key = 1
kv.value = "foo"
To get the values assigned is simple
kv.key
kv.value
It is a simple struct, if you wanna something like python dict you will need to implement a hash struct which will be more complicated.
Related
I'm trying to solve a problem I'm having with a function that will create a new struct objects and then put it in an dynamic array. I have tried multiple variations but i keep running into various problems. This is what I'm working with right now, but I'm getting a memory access problem.
typedef struct {
int keynr;
int access;
time_t lastused;
} keycard;
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0.0;
}
int main () {
keycard *cardList = 0;
cardList = malloc(sizeof(keycard) * 1);
keyCreate(&cardList, 0);
printf("%d", cardList[0].access);
This code gives me: Exception thrown: read access violation.
cardList was 0x64.
I've been reading alot about pointers and memmory allocation but obviously i am missing something..
You if you want to duynamically add new cards to the array, you need to wrap it in another data structure:
typedef struct
{
int keynr;
int access;
time_t lastused;
} keycard;
typedef struct
{
keycard *keyarray;
size_t size;
}keystorage;
int keyCreate(keystorage *cardList, size_t keyid)
{
if (cardList -> keyarray == NULL || keyid + 1 > cardList -> size)
{
keycard *new = realloc(cardList -> keyarray, sizeof(*(cardList -> keyarray)) * (keyid + 1));
if(!new) return -1; //error
cardList -> keyarray = new;
cardList -> size = keyid + 1;
}
cardList -> keyarray[keyid].keynr = keyid + 100;
cardList -> keyarray[keyid].access = 1;
cardList -> keyarray[keyid].lastused = 0.0;
return 0; //OK
}
int main (void) {
keycard key;
keystorage cards = {NULL, 0};
keyCreate(&cards, 500);
printf("%d", cards.keyarray[500].access);
return 0;
}
You are passing the incorrect type to keyCreate. This function expects a pointer to keycard, but you are passing it a double pointer instead. The & means "take the address of", which turns cardList into a keyCard** type. Instead, consider the following:
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard *cardList = malloc(sizeof(keycard) * 1);
// always check if malloc succeeds, and if it does not, handle the error somehow
if (cardList == NULL)
{
fprintf(stderr, "Insufficient mem\n");
return -1;
}
keyCreate(cardList, 0);
printf("%d\n", cardList[0].access); // the \n will flush the output and
// put each item on its own line
// cleanup when you're done, but the OS will do this for you when the
// process exits also
free(keyCreate);
return 0;
}
Also, time_t is most likely a signed integer (What is ultimately a time_t typedef to?), so assigning it to 0.0 is probably not right, but you'll need to check what it typedefs to on your system.
Finally, I assume this is just an MCVE, but I'd advise against mallocing in this case. The 2 primary reasons to malloc are when you don't know how much data you'll need until runtime, or you need "a lot" of data. Neither of those are true in this case. Just from what you've presented, I'd probably do the following:
#define NUM_KEY_CARDS 1
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard cardList[NUM_KEY_CARDS];
for (int keyid=0; keyid<NUM_KEY_CARDS; keyid++)
{
keyCreate(cardList+keyid, keyid);
// or keyCreate(&(cardList[keyid]), keyid);
printf("%d\n", cardList[keyid].access);
}
return 0;
}
i have a task in class to the return an array of struck Symbol from huffman tree.
the function getSL get a huffman tree(only) and return struck of Symbol.
each spot in the array contain a char from the "leaf" of the tree and the
length of his code(how many cross section till the leaf).
my main problem was to find how i advance the cnt of the arry that it will not overright the arry.
thank you.
typedef struct HNode {
char chr;
struct HNode *left, *right;
} HNode;
typedef struct {
char chr;
int counter;
}Symbol;
this is what i did till now.
Symbol * getSL(HNode *root) {
if (root->left == NULL && root->right == NULL) {
Symbol* b = (Symbol*)malloc(100);
b->counter=0;
b->chr = root->chr;
return b;
}
Symbol* a = (Symbol*)malloc(100);
if (root->left != NULL) {
a= getSL(root->left);
a->counter++;
}
if (root->right != NULL) {
a= getSL(root->right);
a->counter++;
}
return a;
}
Apart from the malloc problem (see the comments already), you have a fundamental problem: You allocate a new struct, but then replace it with the one returned from the recursive call. So you lose the one created before (actually, memory leaking!).
Easiest variant would now be converting your Symbol to linked list nodes; then you simply could do:
Symbol* lastLeafFound; // probaly a function parameter!
if(!(root->left || root->right))
{
// leaf found:
Symbol* a = (Symbol*)malloc(sizeof(Symbol));
a->chr = root->chr;
a->counter = /* ... */;
a->next = NULL;
lastLeafFound->next = a;
// you might return a now as last leaf found, using it in the next recursive call
}
Sure, above code is incomplete, but should give you the idea...
If you cannot modify your struct, then you need to create an array and pass it on to every new recursive call (prefer not to use global variables instead):
void doGetSL
(
HNode* root,
Symbol** symbols, // your array to be used
unsigned int* count, // number of symbols contained so far
unsigned int* capacity // maximum possible symbols
)
Passing all data as pointers allows the function to modify them as needed and they are still available from outside...
Symbol* getSL(HNode* root)
{
if(!root)
return NULL;
unsigned int count = 0;
unsigned int capacity = 128;
// allocate a whole array:
Symbol* array = malloc(capacity*sizeof(Symbol));
if(array) // malloc could fail...
{
doGetSL(root, &array, &count, &capacity);
// as you cannot return the number of leaves together with
// the array itself, you will need a sentinel:
array[count].chr = 0;
// obvious enough, I'd say, alternatively you could
// set counter to 0 or -1 (or set both chr and counter)
}
return array;
}
doGetSL will now use above set up "infrastructure":
{
if(!(root->left || root->right))
{
if(*count == *capacity)
{
// no memory left -> we need a larger array!
// store in separate variables:
unsigned int c = *capacity * 2;
Symbol* s = realloc(symbols, c * sizeof(Symbol));
// now we can check, if reallocation was successful
// (on failure, s will be NULL!!!):
if(s)
{
// OK, we can use them...
*symbols = s; // <- need a pointer for (pointer to pointer)!
*capacity = c;
}
else
{
// re-allocation failed!
// -> need appropriate error handling!
}
}
(*symbols)[count].chr = root->chr;
(*symbols)[count].counter = /*...*/;
++*count;
}
else
{
if(root->left)
{
doGetSL(root->left, symbols, count, capacity);
}
if(root->right)
{
doGetSL(root->right, symbols, count, capacity);
}
}
}
One thing yet omitted: setting the counter. That would be quite easy: add another parameter to doGetSL indicating the current depth, which you increment right when entering doGetSL, you can then just assign this value when needed.
You can further improve above variant (especially readability), if you introduce a new struct:
struct SLData
{
Symbol* symbols, // your array to be used
unsigned int count, // number of symbols contained so far
unsigned int capacity // maximum possible symbols
};
and pass this one instead of the three pointers:
doGetSL(HNode*, struct SLData*, unsigned int depth);
struct SLData data =
{
.count = 0;
.capacity = 128;
.array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
doGetSL(root, &data, 0); // again passed as pointer!
I hope I have not oversimplified my code, but what I am basically trying to do is to find the existence of an element in a container, and return the pointer to it.
I have structures like
typedef struct INHs{
int ID;
} INHs;
typedef struct sub_container{
INHs** list_inh;
int nb_list;
} sub_container;
typedef struct container {
sub_container* cont;
int nb_elem;
} container;
And then in my main method I have a container allocated (I will leave it out for simplicity, and a given ID; and for now I won't to iterate over the sub-containers to find my target INHs structure).
INHs** test_INH = NULL;
INHs** return_val = NULL;
int ID = 10;
container* cont; //allocated on all memory
for (uint n=0; !test_INH && n<container_nb_elem; n++){
return_val = find_ptr(&cont[n], ID, &test_INH);
}
INHs** find_ptr(sub_container* sub_cont, int ID, INHs*** test){
INHs** res = NULL;
for (uint i=0; !res && i<sub_cont->nb_list; i++){
if (sub_cont->list_inh[i].ID == ID) {
(*test) = &(sub_cont->list_inh[i]);
res = &(sub_cont->list_inh[i]);
}
return res;
}
I know I don't need both a return value to my element and another one as a function parameter, but these are the two versions I have tried. I don't know what I am doing wrong but valgrind crashes telling me that either "test_INH" or "result_val" are non-initialized, although I am setting them on null.
Does someone see what I am missing here?
typedef struct INHs{
int id;
} INHs;
typedef struct sub_container{
INHs **ptrs;
int nb_list;
} sub_container;
typedef struct container {
sub_container *items;
int nb_elem;
} container;
int main(void)
{
INHs **found = NULL;
int id = 10;
container *cont; //allocated on all memory
for (uint n=0; n < cont->nb_elem; n++){
found = find_ptr( &cont->items[n], id);
if (found) break; /* found it! */
}
if(found) {
/* do something useful with *found ... */
}
return 0;
}
INHs **find_ptr(sub_container *sub_cont, int id)
{
for (uint i=0; i < sub_cont->nb_list; i++){
if (sub_cont->ptrs[i]->id != id) continue;
return &sub_cont->ptrs[i];
}
return NULL;
}
BTW: I find the array of pointers to one integer structures rather strange.
Are these structures all malloc()d separately?
In my binary search tree I want to create a function that can get all words starting with a prefix and store all words in an array called results
this is my tree
struct BinarySearchTree_t
{
char *mot,*def;
struct BinarySearchTree_t *left;
struct BinarySearchTree_t *right;
};
typedef struct BinarySearchTree_t BinarySearchTree;
my function :
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char*** results)
{
BinarySearchTree *tmp;
tmp=tree;
static int size=0;
if (!tmp)
return 0;
else if (strncmp(tmp->mot,prefix,strlen(prefix))==0)
{
(*results)= realloc(*results,(1+size)*sizeof(*(*results)));
(*(*results+size))= malloc(strlen(tmp->mot)*sizeof(char));
strcpy((*results)[size],tmp->mot);
size++;
return (1 + findWordsByPrefix(tmp->left,prefix, &results) + findWordsByPrefix(tmp->right,prefix, &results));
}
else
return (strncmp(tmp->mot,prefix,strlen(prefix))<0)?findWordsByPrefix(tmp->right,prefix, &results):findWordsByPrefix(tmp->left,prefix, &results) ;
}
This function should return a number of words starting with the given prefix.
my problem is that the program crash when it is run , and I don't how to resize my array results
so every time I found a word I should increase the size of the results array .
and I would know how exacly manipulate the pointer of pointer of pointer given in arg of this function (char ***results) : what exactly means?
If I simply compile your code, I get severe compiler warnings including:
1>binarysearchtree.c(98) : warning C4047: 'function' : 'char ***' differs in levels of indirection from 'char ****'
1>binarysearchtree.c(98) : warning C4024: 'findWordsByPrefix' : different types for formal and actual parameter 3
This alone will cause a crash -- you are calling your own function recursively with the wrong arguments.
Next, I believe you need to allocate one more than the length of the string, to hold a copy of a string:
malloc((strlen(tmp->mot) + 1 )*sizeof(char))
Next, you're passing around an array of strings of variable size -- and storing the size in a static variable. It's impossible to know if this will work, so don't do it.
Instead, if you want to use a dynamic array of strings, I suggest extracting out a struct to hold them, like so:
struct ResultTable_t
{
int size;
char **results;
};
typedef struct ResultTable_t ResultTable;
void InitializeResults(ResultTable *p_table)
{
p_table->size = 0;
p_table->results = NULL;
}
void AddResult(ResultTable *p_table, char *result)
{
if (result == NULL)
return;
p_table->size++;
p_table->results = realloc(p_table->results, p_table->size * sizeof(*p_table->results));
p_table->results[p_table->size-1] = malloc((strlen(result) + 1) * sizeof(**p_table->results));
strcpy(p_table->results[p_table->size-1], result);
}
void FreeResults(ResultTable *p_table)
{
if (p_table->results != NULL)
{
int i;
for (i = 0; i < p_table->size; i++)
{
free(p_table->results[i]);
}
free(p_table->results);
}
p_table->size = 0;
p_table->results = NULL;
}
(As an improvement, you might consider using geometric growth instead of linear growth for your table of results.)
Then your function becomes:
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, ResultTable *p_table)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_table, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_table) + findWordsByPrefix(tree->right,prefix, p_table));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_table);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_table);
}
}
And you would use it like:
ResultTable results;
InitializeResults(&results);
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results);
// Do something with the results
// Free all memory of the results
FreeResults(&results);
Update
If the ResultTable is distasteful for some reason, you can pass the dynamic array and array sizes in directly:
void AddResult(char ***p_results, int *p_size, char *word)
{
if (word == NULL)
return;
(*p_size)++;
(*p_results) = realloc(*p_results, ((*p_size)+1) * sizeof(**p_results));
(*p_results)[(*p_size)-1] = malloc((strlen(word) + 1) * sizeof(***p_results));
strcpy((*p_results)[(*p_size)-1], word);
}
void FreeResults(char ***p_results, int *p_size)
{
int i;
if (p_results == NULL || *p_results == NULL)
return;
for (i = 0; i < (*p_size); i++)
{
free ((*p_results)[i]);
}
free (*p_results);
*p_results = NULL;
*p_size = 0;
}
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char ***p_results, int *p_size)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_results, p_size, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_results, p_size) + findWordsByPrefix(tree->right,prefix, p_results, p_size));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_results, p_size);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_results, p_size);
}
}
and use like:
char **results = NULL;
int tablesize = 0;
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results, &tablesize);
// Do something with the results
// Free all memory of the results
FreeResults(&results, &tablesize);
Whew! Long title...here's some pseudo-code to explain that verbiage:
int main(){
int* ptr = function1(); //the data that ptr points to is correct here
function2(ptr);
}
int function2(int* ptr){
//the data that ptr points to is still correct
int i;
for(i=0;i<length;printf("%d\n", (*ptr)[i]), i++); //since ptr points to a contiguous block of memory
function3(ptr);
}
int function3(int* ptr){
//the data that ptr points to is INCORRECT!!!
}
Why would the data in function3 be incorrect?
Note: function1 performs a malloc() and returns the pointer to that memory.
ACTUAL CODE
#include <stdlib.h>
#include <stdio.h>
//Structures
struct hash_table_data_
{
int key, data;
struct hash_table_data_ *next, *prev;
};
struct hash_table_
{
int num_entries;
struct hash_table_data_ **entries;
};
typedef struct hash_table_data_ hash_table_data;
typedef struct hash_table_ hash_table;
//Prototypes
hash_table *new_hash_table(int num_entries);
int hash_table_add(hash_table *ht, int key, int data);
int hash_table_loader(hash_table* ht);
//Main
int main()
{
int num_entries = 8;//THIS MUST BE AUTOMATED
hash_table* ht = new_hash_table(num_entries);
hash_table_loader(ht);
return 0;
}
//Function Definitions
hash_table *new_hash_table(int num_entries)
{
hash_table* ht = (hash_table*) malloc(sizeof(hash_table));
hash_table_data* array = malloc(num_entries * sizeof(hash_table_data));
int i;
for (i=0;i<num_entries;i++)
{
array[i].key = -1;
array[i].data = -1;
array[i].next = NULL;
array[i].prev = NULL;
}
ht->entries = &array;
ht->num_entries = num_entries;
return ht;
}
int hash_table_add(hash_table *ht, int key, int data)
{
//VERIFY THAT THE VALUE ISN'T ALREADY IN THE TABLE!!!!!!!!!!!
int num_entries = ht->num_entries;
hash_table_data* array = *(ht->entries); //array elements are the LL base
int hash_val = key%num_entries;
printf("adding an element now...\n");
printf("current key: %d\n", array[hash_val].key);
int i;
for(i=0;i<num_entries;printf("%d\n", (*(ht->entries))[i].key),i++);//DATA IS INCORRECT!!!!
if (array[hash_val].key == -1)//is this the base link?
{
printf("added a new base link!\n");
array[hash_val].key = key;
array[hash_val].data = data;
array[hash_val].next = NULL;
array[hash_val].prev = &(array[hash_val]);
}
else//since it's not the base link...do stuff
{
hash_table_data* new_link = malloc(sizeof(hash_table_data));
new_link->key = key;//set the key value
new_link->data = data;//set the data value
if (array[hash_val].next == NULL)//we must have the second link
{
printf("added a new second link!\n");
new_link->prev = &(array[hash_val]); //set the new link's previous to be the base link
array[hash_val].next = new_link; //set the first link's next
}
else//we have the 3rd or greater link
{
printf("added a new 3rd or greater link!\n");
hash_table_data next_link_val = *(array[hash_val].next);
while (next_link_val.next != NULL)//follow the links until we reach the last link
{
next_link_val = *(next_link_val.next);//follow the current link to the next
}
//now that we've reached the last link, link it to the new_link
next_link_val.next = new_link; //link the last link to the new link
new_link->prev = &(next_link_val); //link the new link to the last link
}
}
return 0;
}
int hash_table_loader(hash_table* ht)
{
int i;
for(i=0;i<(ht->num_entries);printf("%d\n", (*(ht->entries))[i].key),i++); //DATA IS STILL CORRECT HERE
FILE *infile;
infile = fopen("input.txt", "r");
while(!feof(infile))
{
int key,data;
fscanf(infile, "%d %d", &key, &data);
hash_table_add(ht, key, data);
}
fclose(infile);
}
Note: Issue occurring the first time hash_table_add() is called.
Your first problem is here:
ht->entries = &array;
You cause the structure to hold a hash_table_data** which points to the variable hash_table_data* array which is local to the function; then you exit the function and return a pointer to the structure. The structure still exists (it was allocated via malloc(), and the stuff that array points to still exists, but array itself does not. Accordingly, this pointer within the structure is now invalid.
As far as I can tell, there is no reason for you to be holding a pointer-to-pointer here. Just use hash_table_data* as the entries type, and copy array into that struct member. Pointers are values too.
I guess you iterate incorrectly
for(i=0;i<length;printf("%d\n", (*ptr)[i]), i++);
this is nonsense.
You should rewrite it as this:
for(i=0;i<length;i++)
printf("%d\n", ptr[i]);
(*ptr)[i] is just wrong, it doesn't make sense if you think about it.
*ptr is the first element of the pointed-to array of ints.
ptr[i] is thi ith one, this is what you need.
Please, read Section 6 carefully.
A couple of advises based on this question:
Don't write overcomplicated code like this for statement with comma operator used, it just rarely needed and leads not only to confusion, but to mistakes (although no mistakes with it in this particular example)
Look carefully for mistakes, don't blame everything on functions. If your code doesn't work, try finding the exact place which is wrong and prove it. In this example people who tested your code were right: functions are definitely not the cause of the error.
hash_table *new_hash_table(int num_entries)
{
hash_table* ht = (hash_table*) malloc(sizeof(hash_table));
hash_table_data* array = malloc(num_entries * sizeof(hash_table_data));
// ....
ht->entries = &array; // Problem
// ...
return ht;
} // Life time of array ends at this point.
You are taking the reference of the local variable array and assigning it to ht->entries which is no more valid once the function returns.