Function is waiting for a pointer but I want to return an integer in the function lookup (i can't modify the return type of the function), what can i do to solve this problem ?
int hashtable_insert(HashTable ** ptable, void *data, void (*delete) (void *))
{
if(hashtable_lookup(*ptable, data) != -1){
return -1;
}
data = malloc(sizeof(size_t));
list_append((*ptable)->list, data, (*ptable)->size);
_hashtable_resize(ptable);
return 0;
}
warning: comparison between pointer and integer
if(hashtable_lookup(*ptable, data) != -1){
void * hashtable_lookup(HashTable * table, void *data)
{
for(int i = 0; i < (table)->length; i++){
if((table)->list[i] == data){
return data;
}
}
return -1;
}
warning: return makes pointer from integer without a cast [-Wint-conversion]
return -1;
Function is waiting for a pointer but I want to return an integer in the function lookup (i can't modify the return type of the function), what can i do to solve this problem ?
If the function returns void * and you cannot change that, then returning an integer simply is not an option. You could return an integer converted to a pointer (and compare the return value against a similar value), but unless your hash table supports null values, a null pointer would make a better failure code:
void * hashtable_lookup(HashTable * table, void *data) {
// look up data ...
// lookup failed
return NULL;
}
// ...
if (hashtable_lookup(*ptable, data) != NULL) {
// data is already present in the hash table
return -1;
}
But if a null pointer would be valid data for the table, then
void * hashtable_lookup(HashTable * table, void *data) {
// look up data ...
// lookup failed
return (void *) -1;
}
// ...
if (hashtable_lookup(*ptable, data) != (void *) -1) {
// data is already present in the hash table
return -1;
}
First warning is because you are comparing a void* to an int. The second one is because you're returning an int instead of a pointer.
You could add casts here and there to remove the warnings (if(hashtable_lookup(*ptable, data) != (void*)(-1)){ and return (void*)(-1);, but it would be harder to read and more error-prone since you usually check pointers to not be NULL, but not to be different than "-1".
Typically, you would return a NULL pointer to indicate that the function failed. Also, you might have if(hashtable_lookup(*ptable, data) != -1){ wrong since it looks like when hasthable_lookup() returns -1 it failed.
I think this is what you are looking for.
int hashtable_insert(HashTable ** ptable, void *data, void (*delete) (void *))
{
if(hashtable_lookup(*ptable, data) == NULL){
return -1;
}
data = malloc(sizeof(size_t));
list_append((*ptable)->list, data, (*ptable)->size);
_hashtable_resize(ptable);
return 0;
}
void * hashtable_lookup(HashTable * table, void *data)
{
for(int i = 0; i < (table)->length; i++){
if((table)->list[i] == data){
return data;
}
}
return NULL;
}
Related
I am working off some skeleton code for a hash table implementation. In the main class, there is a portion which checks for the key in the table. It allows for duplicates so the it is expecting to return an array of a specified size, and if the entries exceed that size then it is called again with a larger array. My issue is with the "num_results" pointer which is declared just before.
int num_values = 1;
valType* values = malloc(1 * sizeof(valType));
int* num_results = NULL;
get(ht, key, values, num_values, num_results);
printf("num_results: %d\n", (*num_results));
if ((*num_results) > num_values) {
values = realloc(values, (*num_results) * sizeof(valType));
get(ht, 0, values, num_values, num_results);
}
for (int i = 0; i < (*num_results); i++) {
printf("value of %d is %d \n", i, values[i]);
}
free(values);
It is declared to null (presumably because if there are no results then the memory isn't wasted?)
int get(hashtable* ht, keyType key, valType *values, int num_values, int* num_results) {
int slot = key % sizeof(ht);
struct node *entry = ht->entries[slot];
if(entry == NULL){
printf("There are no matching hashed keys");
return -1;
}
// Allocate the num_results, as just a NULL pointer was passed
if((num_results = malloc(sizeof(int))) == NULL){
return -1;
}
// Start it at 0 so that it cxan be incremented as we check
(*num_results) = 0;
printf("num_results: %d\n", (*num_results));
int temp = num_values;
while(entry != NULL){
if(entry->key == key){
++(*num_results);
if(temp != 0){
values[num_values-temp] = entry->value;
--temp;
}
}
entry = entry->next;
}
printf("num_results: %d\n", (*num_results));
return 0;
}
This is the get function, and as you can see I allocate the memory needed, set it to 0, and it increments as expected. The output looks like:
num_results: 0
num_results: 2
num_results: 73896
This confuses me, as clearly the 2 result is from the last line of the method, and the last printout comes immediately after returning to the main... What is happening here? Why is the value changing?
You have to pass the pointer num_results by reference. Otherwise the function deals with a copy of the pointer.
For example
int get(hashtable* ht, keyType key, valType *values, int num_values, int ** num_results) {
// ...
if(( *num_results = malloc(sizeof(int))) == NULL){
return -1;
}
//…
A function call will look like
get(ht, key, values, num_values, &num_results);
Actually I do not see a great sense to declare the variable num_results as a pointer and allocate dynamically a memory for it in the function. I would declare it at least as having the type unsigned int.
For example
unsigned int num_results = 0;
and then the function get could look like
int get(hashtable* ht, keyType key, valType *values, int num_values, unsigned int *num_results) {
//…
*num_results = 0;
//…
and called like
get(ht, key, values, num_values, &num_results);
Pay attention to that instead of
int slot = key % sizeof(ht);
it seems you mean
int slot = key % sizeof( *ht);
i have decleard a structure and allocate some memory too . using a function i update datas . i got error segmentation fault when i acssing data.
This is my code
In headerfile :
typedef struct
{
int member;
char *name;
}place;
void update(place **,int);
void display(place **,int);
in function
static memallocate(place **ptr,int viname,int index)
{
ptr[index]=(place *)malloc(sizeof(place));
ptr[index]->name=(char *)malloc(viname*sizeof(char *));
}
void update(place **ptr,int index)
{
---read string value "na" find the strlen as "pp"---
memallocate(ptr,pp,index);
ptr[index]->name=na;
}
void display(place **ptr,int index)
{
int i;
for(i=0;i<index;i++)
{
printf("%s\n",ptr[i]->name);
printf("%s\n",ptr[i]->country);
}
}
in main file :
void main()
{
int index=0;
place *pla[5]={NULL};
while(index<2)
{
update(&pla[index],index);
index++;
}
display(pla,index);
}
my problem is i got segmentation fault when acessing function display and can't print datas ptr[0]->name,ptr[0]->country,ptr[1]->name,ptr[1]->country ..why this happen ? any memory fault . I got printing when i use printf after each updation .
I see two mayor issues here.
1st
Here
static void memallocate(place **ptr,int viname,int index)
{
ptr[index]=(place *)malloc(sizeof(place));
ptr[index]->name=(char *)malloc(viname*sizeof(char *));
}
you allocate too much memory. It shall be
static void memallocate(place ** ptr, int viname, int index)
{
ptr[index] = malloc(sizeof(place));
ptr[index]->name = malloc(viname * sizeof(char));
}
or even better:
static int memallocate(place ** ptr, size_t viname, size_t index)
{
int result = 0;
if (NULL == ptr)
{
result = -1;
errno = EINVAL;
}
else
{
ptr[index] = malloc(sizeof *ptr[index]);
if (NULL == ptr[index])
{
result = -1;
}
else
{
ptr[index]->name = malloc(viname * sizeof *(ptr[index]->name));
if (NULL == ptr[index]->name)
{
result = -1;
free(ptr[index]);
}
}
}
return result;
}
2nd
Then here (assuming na to be a char* properly initilaised to reference a C-"string")
void update(place **ptr,int index)
{
---read string value "na" find the strlen as "pp"---
memallocate(ptr,pp,index);
ptr[index]->name=na;
}
you overwrite what you just assigned to name. To copy a C-"string" use strcpy().
int update(place ** ptr, size_t index)
{
---read string value "na" find the strlen as "pp"---
int result = memallocate(ptr, pp, index)
if (-1 == result)
{
perror("memallocate() failed");
}
else
{
strcpy(ptr[index]->name, na);
}
return result;
}
Then call it like this:
int main(void)
{
size_t index = 0;
place * pla[5] = {NULL};
/* Loop over all array's elements. */
while (index < sizeof pla/sizeof *pla)
{
update(pla, index);
++index;
}
...
}
Notes:
Always check the outcome of relevant function calls (here malloc()) and design your functions to be able to pass failures up to the caller.
Do not cast the result of malloc(), calloc() and realloc() in C. It is not needed nor recommended.
Prefer using size_t over int for memory sizes and indexes. size_t does not waste a bit for negative numbers and it is guaranteed to be large enough to address any arrays' element or represent any memory size. sizeof as well as strlen() return size_t not int for example.
When you call your update(), you are passing a place ** of the current index as argument.
However, you nevertheless pass index too and later in your memallocate() allocate memory as if it was a pointer to the place *[].
So it should help to remove the parameter index from update() and memallocate() and change the memory allocation to something like:
*ptr = (place *)malloc(sizeof(place));
*ptr->name = (char *)malloc(viname*sizeof(char *));
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);
typedef char* string;
int func1(string s);
char* func2(); // returns a new memory/
if(func1(func2()) == 4)
{
// code
}
Assuming func2() is only needed in the condition. Since i need to free newly allocated memory, how can i free it up within the same line(i.e. with the same condition or paranthesis) ? My motiviton for this is to keep the code clean.
EDIT 1.
Yes it is a c question. The use of "string" type was error on my part as i have always typedef it to char*. Sorry for the confusion.
To do this cleanly, make a new function that does the work in a clear manner:
static int func3()
{
char *s = func2();
int result = func1(s);
free(s);
return result;
}
…
if (func3() == 4)
…
(Presumably, there is some assurance that func2 successfully allocates memory. If not, you must test its return value.)
Free it in the same line with no new function definitions:
int result;
char *temp;
/* comma operator: evaluate these 4 expressions left-to-right,
and the value is the value of the last expression */
if(temp = func2(), result = (func1(temp) == 4), free(temp), result)
{
/* Do things */
}
Cleaner code:
int func3(void)
{
char *temp;
int result;
temp = func2();
result = func1(temp);
free(temp);
return result;
}
/* ... */
if(func3() == 4)
{
/* do things */
}
Here is a solution using a functional approach:
int apply_free(int (*f1)(char*), char * (*f2)()) {
char *s = f2();
if (s != NULL) {
int result = f1(s);
free(s);
return result;
}
else {
return -1; /* or any meaningful value if f2 returned a NULL pointer */
}
}
if (apply_free(func1, func2) == 4)
{
// code
}
This assumes your various cases will have the same type signature.
Code:
struct company_struct
{
company_name_t company_name;
double stock_price;
company_stock_t company_stock;
};
typedef struct company_struct company_struct_t;
int sort_by_price(const void * ptr1, const void * ptr2)
{
assert(ptr1 != NULL);
assert(ptr2 != NULL);
const company_struct_t * ptr1_price = (const company_struct_t *) ptr1;
const company_struct_t * ptr2_price = (const company_struct_t *) ptr2;
assert(ptr1_price->stock_price != NULL); //??? Why it failed?
assert(ptr2_price->stock_price != NULL);
if(ptr1_price->stock_price > ptr2_price->stock_price) return -1;
else if (ptr1_price->stock_price == ptr2_price->stock_price) return 0;
else if (ptr1_price->stock_price < ptr2_price->stock_price) return 1;
}
qsort(company_list, *size, sizeof(company_list), sort_by_price);
When I run my program, the assert failed. I am relatively new to C, please bear with me.
You need to pass the size of an individual element as the third parameter of qsort, like this:
qsort(company_list, *size, sizeof(company_struct_t), sort_by_price);
Also make sure that size points to an int that holds the number of items to be sorted.
If it really is this line that's failing,
assert(ptr1_price->stock_price != NULL); //??? Why it failed?
you should crank-up your compiler warnings. You should get a warning for comparing a double to a pointer. [And for prices, it's usually better to use an integer. What would $0.000003 mean?]