Unsual Result when passing pointer as argument - c

I have implemented a hashmap.
struct hashmap_elmnts
{ char *key;
int in_use;
void *data; //contains the address of the malloc of struct ussd defined below
};
struct hashmap_map
{
int table_sizel;
int size;
struct hashmap_elmnts *element ;
};
Now, I have another structure USSD
typedef struct ussd { char menu;
int8_t did;
int8_t invokeid;
char *language;
char *msisdn;
char *ussd_string;
} USSD;
Now, while inserting in the HASHMAP,
USSD *init = (USSD*)malloc(sizeof(USSD));
init->msisdn = (char*)malloc(sizeof(char));
init->language = (char*)malloc(sizeof(char));
init->ussd_string = (char*)malloc(sizeof(char));
msisdn = language = ussd_string = NULL;
Then, I assign some values and then insert in the hashmap
However, while getting the information back, i face some issue:
IN FILE GET.c
I call a function
USSD *pointer = NULL;
res = hashget(key, pointer);
if (pointer == NULL)
printf ("pointer fail\n");
else
printf ("pointer pass\n");
IN FILE HASHGET.c
int hashget(int key, USSD_STRUCT *arg)
{
/** declaring a hashmap_map pointer **/
struct hashmap_map *m;
now, after various calculation -> i find a value of 'curr'
arg = (m->element[curr].data);
if (arg == NULL)
printf("fail\n");
else
printf ("pass\n"):
return 1;
}
THE OUTPUT IS AS FOLLOWS:
pass
pointer fail
How is this possible, when arg != NULL but still the pointer is NULL. As i expected any assignment at arg would be reflected in pointer also.
Can anybody let me what could have gone wrong. I'm unable to share the entire code snippets as the code is huge..

In your first block of code you are saying you if assign null to pointer not if pointer equals null.

if (pointer = NULL)
This is your problem. If your compiler isn't warning you about this, either turn your warnings up, or find a better compiler. What you want is what you have in your second if block:
if (pointer == NULL)
The reason it isn't working with the one = is because you are assigning NULL to pointer within the if statement. The result of that expression is NULL, hence the if block doesn't execute, but the else block does.
Alternatively, some people find it easier to read by omitting the comparison to NULL altogether:
if (pointer)
{
// pointer is not NULL
}
else
{
// pointer is NULL
}

Use this way (Make following changes at respective places)
...
res = hashget(key, &pointer);
if (pointer == NULL)
printf ("pointer fail\n");
else
printf ("pointer pass\n");
...
...
int hashget(int key, USSD_STRUCT *arg)
...
...
*arg = data;
if (*arg == NULL)
printf("fail\n");
else
printf ("pass\n"):
return 1;
}
...
Reason:
In your program you are passing pointer as pass by value, In my method I am passing as pass by pointer or basically passing the address of pointer because its value needs to be modified in calling function.
EDIT: (After your modification in the question)
USSD init = (USSD)malloc(sizeof(USSD));
This is wrong. init should be a pointer.
Use USSD *init = (USSD*)malloc(sizeof(USSD));.
And after you allocated memory to init->msisdn, init->language, init->ussd_string, why are you setting them to NULL, that too just by referencing the inner variables of struct like this: msisdn = language = ussd_string = NULL.
And even if you correct all these mistakes, my answer is OK, since you cannot modify value of pointer by making a call like this: res = hashget(key, pointer);, using this you can only modify *pointer i.e. value pointed to by the pointer.

Related

Segmentation fault when strdupa void pointer

I'm fairly new to pointers, and void pointers is still black art to me.
In the following code I get a segfault when tmp->item = strdup(item);
I'm not sure how to fix.
int springmap_add(SpringMap *sm, char *key, void *item) {
SpringMap *tmp = sm;
.
.
.
while (tmp) {
if (!tmp->next) {
tmp->next = springmap_init();
tmp->next->key = strdup(key);
tmp->next->item = strdup(item); // Segfault here
return 1;
}
tmp = tmp->next;
}
return 0
}
int main(int argc, char* argv[]) {
char* key[ESTS] = {"alpha"};
void* ptr[ESTS] = {(void*)0xdeadbeef};
SpringMap* map = springmap_init();
for(int i = 0; i < TESTS; i++) {
int status = springmap_add(map, key[i], ptr[i]);
}
springmap_free(map);
return 0;
I'm not up to speed on void pointers.
The function name already tells: strdup composes of string duplicate, and it only is able to duplicate null-terminated C-strings (well, admittedly any data as long as it contains a null byte somewhere, though it would get cut off too early unless this null byte was the very last byte within the data).
void pointers in C have the unfortunate nature of implicitly converting to any other pointer type, happening in your code as well. However these pointers do not point to null-terminated C-strings, actually, they aren't even valid at all (most of most likely, at least)! Thus trying to read from them yields undefined behaviour.
So at first make sure that your void pointers point to valid memory. To use strdup they should point to C-strings, otherwise memcpy is the way to go, though you need to malloc storage space as target first. For both, you need the size of the object available, though. However you cannot get that back from the void pointer any more, thus you need yet another parameter.
You could write your own objdup function covering the duplication:
void* objdup(size_t size, void* object)
{
void* copy = malloc(size);
if(copy)
{
memcpy(copy, object, size);
}
return copy;
}
Still your pointers need to be valid! Some possible example might look like:
int main()
{
SomeDataType o1;
AnotherDataType o2;
AnotherDatatType* ptr = &o2; // create a valid pointer
// (could be done by malloc'ing memory, too)
void* c1 = objdup(sizeof(o1), &o1);
// ^ take the address of a REAL object!
if(c1)
{
void* c2 = objdup(sizeof(*o2), o2); // or via pointer to REAL object
if(c2)
{
// ...
free(c2);
}
free(c1);
}
return 0;
}

Passing string to init function and storing it in a malloc'd struct

I am writing an init function to initializes the first node in a linked list. I am trying to add a string name to label each node but am getting weird behavior when the function returns. I am passing the string directly into the function, mallocing another char* of the same length then strcpy'ing the input string into this new location. I am trying to store it in a char** within the struct. It copies into the struct whilst within the init function but once it returns the string changes, which appears like the memory frees upon returning the init function.
typedef struct {
key_grid_TypeDef* grid;
char** name;
uint8_t ID;
void* next;
void* prev;
} keymap_layer;
keymap_err_TypeDef keymap_init( keymap_list* layer_list,
key_grid_TypeDef* grid, char* layer_name ){
//init initial layer
keymap_layer *layer = (keymap_layer*) malloc (sizeof(keymap_layer));
if (layer == NULL)
return km_init_err;
char* mal_name = (char*)
malloc((strlen(layer_name)+1)*sizeof(char));
if (mal_name == NULL)
return km_init_err;
strcpy(mal_name,layer_name);
layer->name = &mal_name;
if(sizeof(keymap0) == sizeof(*layer->grid))
memcpy(&layer->grid, &grid, KEYBOARD_ROWS * KEYBOARD_COLS);
else{
free(layer);
return km_init_err;
}
return km_ok;}
in my task
ret = keymap_init(&key_layer_list, &keymap0, "Initial layer");
Thanks
This is highly fishy:
char* mal_name = (char*) malloc((strlen(layer_name)+1)*sizeof(char));
if (mal_name == NULL)
return km_init_err;
strcpy(mal_name,layer_name);
layer->name = &mal_name;
The local variable mal_name ceases to exist as soon as the keymap_init function terminates, so you are storing a pointer to that variable.
You should do this:
typedef struct {
...
char* name; // just a simple pointer to char
...
} keymap_layer;
...
layer->name = malloc((strlen(layer_name)+1)*sizeof(char));
strcpy(layer->name, layer_name);
If you want to change the string stored in layer->name later, use realloc.
For example:
...
layer->name = realloc(layer->name, (strlen(new_name)+1)*sizeof(char));
strcpy(layer->name, new_name);
...
Disclamer: there is no error checking for brevity.
BTW: you don't cast the return value of mallocand friends.

Failing to alloc memory received by a pointer linux

I have a function that receives by a pointer the location where will be stored. This place can have different other similar structs.The function has to read a file. This file have stored a struct, which i need to read.
typedef struct user_manage_t{
short int user_id;
char permission;
long int other_id;
long int check;
}user_manage_t;
typedef struct holder_t{
user_manage_t *user_manage;
user_manage_t *user_manage_backup;
//(...)and a lot of stuff
}holder_t;
holder_t holder;
int db_read_from_file(user_manage_t *prt){
DEBUG_PRINT("READ_FROM file started");
FILE *fd_read;
char buffer[480];
int read, bytesRead=0;
int num;
const struct user_manage_t *header;
fd_read = fopen("/home/user/user_list","r+b");
if (fd_read == NULL)
{
printf("Error");
}
else
{
DEBUG_PRINT("Its open!!!");
}
do
{
read=fread(buffer, 2, 90, fd_read);
bytesRead=bytesRead+read;
DEBUG_PRINT("Number of bytes lidos read=%d",bytesRead);
}while(read!=0); //(bytesRead < 480);
header = (struct user_manage_t *) (buffer);
fclose(fd_read);
if ( NULL == ( prt = calloc( 10, sizeof(user_manage_t))))//aloca
{
DEBUG_PRINT("MAJOR_ERROR: couldnt allocate mem to users");
return -1;
}
else
{
memcpy( (struct user_manage_t *) &prt, &buffer, 90);
DEBUG_PRINT("Users copied to main list");
for ( short int i=0;i<4 ; i++ )
{
DEBUG_PRINT("i= %hd",i);
DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id );
DEBUG_PRINT("Permission: %d",holder.user_manage[i].permission);
DEBUG_PRINT("other_ID:%ld",holder.user_manage[i].other_id);
DEBUG_PRINT("Check_value:%ld", holder.user_manage[i].check);
}
return 1;
}
}
main(){
db_read_from_file((struct user_manage_t *) &holer.user_manage);
db_read_from_file((struct user_manage_t *) &holder.user_manage_backup);
}
When I run the code I get SEGFAULT and valgrind tell me this,
Thread 2:
==2746== Invalid read of size 2
==2746== at 0x80523B4: db_read_from_file (code.c:3069)
==2746== by 0x20303333: ???
==2746== Address 0x0 is not stack'd, malloc'd or (recently) free'd
This is the line of "DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id );" So obviously looks like I am not storing it in the right place.
Can u help me?
Priority Nr 1
After looking at your code a bit more, I suspect you're casting as much as you do, because you kept getting compiler warnings about "incompatible [pointer] types" and the like. Those warnings exist for a reason: there's an issue, a possible source for bugs there. Don't hush it up, don't ignore it: FIX IT!
Yes, sometimes those casts are required, and sometimes compilers complain about your code when you know what you're doing. In that case, you can add a cast, but don't think of those casts as compiler-gags: they are ways to tell the compiler that you know what you're doing. You've just gone cast-crazy to get the compiler to shut up. That's bad.
Next
In both your db_read_from_file calls from main, you are passing pointer to a null pointer to your function. That means you still have to allocate memory to actually go and store that data, or you have to redefine holder to something like:
struct
{
user_manage_t user_manage;//not pointers, actual structs
user_manage_t user_manage_backup;
} holder;
If you keep them as pointers, just allocate all members of holder in main:
holder.user_manage = malloc(sizeof *holder.user_manage);//and so on
//preferably, though:
if (NULL == (holder.user_manage_backup = malloc(sizeof *holder.user_manage_backup))
exit (EXIT_FAILURE);//error
The big one
As sth already mentioned:
memcpy( (struct user_manage_t *) &prt, &buffer, 90);
You are passing &prt, which reads: address of prt. This variable in itself is already a pointer, the memory address of a pointer is, again, a pointer. A pointer to a pointer (double indirection, avoid if possible...). Now as if that weren't enough: look at what you pass to your function:
db_read_from_file(&holder.user_manage);
Keep in mind that holder.user_manage already is a pointer, you are passing a pointer to a pointer! Thats double indirection. Then, you pass a pointer to this pointer to a pointer to memcpy!! Yes, you may have to read this last sentence again. But in short: you are passing a pointer, to a pointer, to a pointer to a struct, where that last bit (the pointer to a struct) could just be a null-pointer, too!
So what you have is this:
memcpy(void ***, char *, 90);//where the prt is void ***, and **prt could be NULL
Think about memcpy as a function that, basically does this:
void * memcpy( void *target, const void *src, size_t nr_of_bytes)
{
char *dest = target;
char *from = src;//use char, as it is guaranteed to be 1 byte in size
int i;
while(nr_of_bytes--)
*dest++ = *from++;//copy byte to destination, move pointer 1 byte
return dest;//return destination
}
Notice that the destination is being dereferenced (*dest++). If you pass a pointer to a pointer(&prt), and dereference it, you end up with a pointer, right? That's what you are writing to => *(&prt) == prt!
The cast, and the way you use it suggest you believe you're writing to whatever prt is pointing to, while in fact you are trying to write 90 bytes to whatever the pointer to prt is pointing to. And it's pointing to prt, which in turn points to a pointer. Only after this third inderiction, we find the struct... that's just crazy.
Anyway, the size of a pointer is 4 bytes on a 32 bit system, 8 on 64 bits. You are copying 90 bytes, so you probably end up in memory you shouldn't mess with.
Replace your code with this:
memcpy(*prt, buffer, sizeof *prt);//copy max the sizeof whatever prt is pointing to
And change the db_read_from_file function to this:
int db_read_from_file(user_manage_t **prt)//pointer to pointer!
And keep in mind that, whenever you want to change something of the struct that prt points to (2nd level), you have to dereference it, to get a regular pointer. For example, allocating memory:
if ( NULL == ( prt = calloc( 10, sizeof(user_manage_t))))//aloca
Has to become:
if ( NULL == ( *prt = calloc( 10, sizeof(user_manage_t))))//aloca
However, this is still wrong in many ways. What you actually need, is realloc, because prt might already be pointing at allocated memory:
*prt = realloc(*prt, 10*sizeof **prt);
if (*prt == NULL)
//ERROR
It's cleaner, and safer.
Also check if your function isn't being passed a null pointer, do away with needless casts (they're clutter), and always check the return value of functions!
Here's the final code, in case some one stumbles in a similar situaion:
typedef struct user_manage_t{
short int user_id;
char permission;
long int other_id;
long int check;
}user_manage_t;
typedef struct holder_t{
user_manage_t *user_manage;
user_manage_t *user_manage_backup;
pthread_mutex_t check_mutex;
pthread_mutex_t backup_mutex;
//(...)and a lot of stuff
}holder_t;
holder_t holder;
int db_read_from_file(user_manage_t **prt, pthread_mutex_t mtx){
DEBUG_PRINT("READ_FROM file started");
FILE *fd_read;
char buffer[480];
int read, bytesRead=0;
int num;
const struct user_manage_t *header;
fd_read = fopen("/home/user/user_list","r+b");
if (fd_read == NULL)
{
printf("Error");
}
else
{
DEBUG_PRINT("Its open!!!");
}
do
{
read=fread(buffer, 1, 480, fd_read);
bytesRead=bytesRead+read;
DEBUG_PRINT("Number of bytes lidos read=%d",read);
}while(read!=0); //(bytesRead < 480);
header = (struct user_manage_t *) (buffer);
fclose(fd_read);
if ( NULL != prt )
{
status = pthread_mutex_trylock (&mtx);
if (status != 0)//compor isto
{
DEBUG_PRINT("ERROR with lock");
return -1;
}
else
{
num = bytesRead / sizeof(user_manage_t);
DEBUG_PRINT("prt is not null and num=%d",num);
//should add an if to check if num >0
//if ( NULL == ( *prt = calloc( num, sizeof(user_manage_t))))//aloca
if ( NULL == ( *prt = malloc(bytesRead)))
{
DEBUG_PRINT("MAJOR_ERROR: couldnt allocate mem to users");
status = pthread_mutex_unlock(&mtx);
return -1;
}
else
{
//memcpy( *prt, header, sizeof(**prt));
memcpy( *prt, header, bytesRead);
DEBUG_PRINT("Users copied to main list");
status = pthread_mutex_unlock(&mtx);
for ( short int i=0;i<4 ; i++ )
{
DEBUG_PRINT("i= %hd",i);
DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id );
DEBUG_PRINT("Permission: %d",holder.user_manage[i].permission);
DEBUG_PRINT("other_ID:%ld",holder.user_manage[i].other_id);
DEBUG_PRINT("Check_value:%ld", holder.user_manage[i].check);
}
return 1;
}
}
}
if ( NULL == prt )
{
DEBUG_PRINT("Pointer is null!");
return 0;
}
}
main(){
db_read_from_file(&holer.user_manage, holder.check_mutex);
db_read_from_file(&holder.user_manage_backup, holder.backup_mutex);
}
I am not sure if I am checking the null prt well, but the rest is working.
I made a small changes to be "perfect" is only missing thing is sending the filename as input of the function.It looks like the mutex is working with 100% sure.

Seg Fault when copying a pointer

How come the following code result in seg fault? Basically after I copy the head pointer to temp, the head pointer gone.
typedef struct address * paddress; // defines struct pointer
void addAddressToList(paddress head, int addr[])
{
if (head == NULL) {
//head->addrArray = addr; // if list is initially empty
} else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
paddress newAddress = (paddress)malloc(sizeof(paddress*));
newAddress->intAddr = addr;
newAddress->right = NULL;
newAddress->left = temp; // connect the new address
temp->right = newAddress;
}
}
main() {
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
int intAddr1[] = {1,2,3,4,5,6,7};
char hexAddr1[] = "123456";
int intAddr2[] = {16,14,13,12,11};
char hexAddr2[] = "fedcb";
addressListHead->intAddr = intAddr1;
addressListHead->hexAddr = hexAddr1;
addAddressToList(addressListHead, intAddr2);
}
paddress addressListHead;
addressListHead = (paddress)malloc(sizeof(paddress*));
It seems to get rid of the compilation error, you have type casted what malloc is returning to paddress. addressListHead is a pointer, which means it can hold the address of an object but not the address of a pointer. The malloc here statement doesn't create an object. You need to change this -
addressListHead = (paddress)malloc(sizeof(paddress*));
to
addressListHead = (paddress)malloc(sizeof(struct address));
in main and addAddressToList functions.
Segmentation fault :
else {
paddress temp;
temp = head;
while (temp->right != NULL) {
temp = temp->right; // go to end of the list
}
I understand paddress::right is a pointer with the fact you are comparing it to NULL. But what is temp::right is initialized to. It is pointing to some garbage address and so you cannot ask for it to compare with NULL. Make it point to a valid memory location.
There is more than one problem in your code.
Firstly, the usual advice: stop using sizeof with type names (as much as possible). Use sizeof with expressions, not types. Type names belong in declarations and nowhere else.
Your problem with memory allocation could have been prevented if you used this malloc idiom
T *p = malloc(n * sizeof *p);
i.e. sizeof should be applied to *p, where p is the pointer to the array you are allocating and n is the total number of elements in that array. That way you never have to guess what type name you should specify under sizeof (an that way your code becomes type-independent).
In your case you are allocating just one object, so the code should look as
paddress newAddress = malloc(sizeof *newAddress);
(And don't cast the result of malloc - there's absolutely no point in doing that).
Secondly, when you the head element of the list, you need to initialize all the fields. Yet you never initialize right (or left) in the head element. Hence the crash even when the correct amount of memory is allocated.
In main(), you want
addressListHead = (paddress)malloc(sizeof(address));
That makes sure you get enough bytes to hold an address.
First error:
addressListHead = (paddress)malloc(sizeof(paddress*));
paddress* means a pointer to paddress which itself is a pointer to struct address. Hence paddress* is a pointer to a pointer to struct address. You would want to do:
addressListHead = (paddress)malloc(sizeof(struct address));
Also, I see that you made a similar mistake yesterday. Why do I get a seg fault? I want to put a char array pointer inside a struct
It's important to understand the concept of pointers properly. I would definitely recommend you to go through some tutorials on pointers. If you need help with that, let me know.

Returning a pointer to an array of pointers to structs

So, I'm having a little problem. I'm trying to build a hash table, but I keep getting an error saying "return from incompatible pointer type." I know what this means, but I don't know why my code isn't working. I'm looking for an explanation of why my code does not work. Why does it not recognize the array as a pointer?
I'm making an array of pointers to structs for a hash table. (externally chained)
(I know that my code probably really sucks >< I'm still learning!)
struct hashTBL {
char *userID;
char *password;
struct hashTBL *next;
};
typedef struct hashTBL Tbl;
typedef struct hashTBL* TblPTR;
TblPTR createHashTBL(int size)
{
char *userID;
char *password;
int i;
TblPTR hashArray[size];
FILE* fpData;
char *fileName = "encrypted.txt";
fpData = openReadFile(fileName);
TblPTR T = NULL;
while((fscanf(fpData, "%s", userID)) != EOF)
{
fscanf(fpData, "%s", password);
i = hash(userID, size);
if(hashArray[i] != NULL)
{
TblPTR H = hashArray[i];
while(H != NULL)
{
T = H;
H = H->next;
}
H = newPTR(userID, password, T);
}
else
{
hashArray[i] = newPTR(userID, password, T);
}
}
closeFile(fpData);
return &hashArray;
}
TblPTR newPTR(char *userID, char *password, TblPTR T)
{
TblPTR H = (TblPTR)malloc(sizeof(Tbl));
if(T != NULL) T->next = H;
H->userID = userID;
H->password = password;
H->next = NULL;
return H;
}
You have at least two problems.
First, your createHashTBL() function is defined to return a TblPTR object, and you're returning a pointer to an array of TblPTR objects. You should change the function type to match the return type you're trying for, or return the right type of object.
Second, your hashArray is stack-allocated within the createHashTBL() function, which means you can't return a pointer to it. It will go away when your function returns. You should try allocating the array with malloc() or having the caller provide a pointer to a pre-allocated array.
TblPTR hashArray[size]; is created on the stack and cannot be returned, because your variable will be destroyed at the end of your function.
You should use malloc() instead, or static TblPTR hashArray[size]; (not recommended).
And this is wrong :
return &hashArray;
You are returning a pointer to your array : (TblPTR*). Just do
return hashArray;
Your compiler error hints that it might also be another problem too, such as a missing typedef. You should always copy/paste error messages so we can inspect them, as well as indicating which line the error is on in the code you paste - this will help everyone in understanding the problem
There's some errors here though.
TblPTR createHashTBL(int size) {
...
TblPTR hashArray[size];
..
return &hashArray;
}
You cannot return a pointer to a local variable - that variable is gone when the function returns
createHashTable is declared to return a TblPTR, but return &hashArray; has a completely different type, it's a pointer to an array of TblPTR.
That function should probably be
TblPTR *createHashTBL(int size) {
...
TblPTR *hashArray = malloc(size * sizeof *hashArray);
..
return hashArray;
}
(Remember to free() the elements and the hashArray when you're done with it)
You have two major problems:
The type of the expression &hashArray is TblPTR (*)[size] (pointer to size-element array of TblPTR), not TblPTR; that's where your type mismatch warning comes from. However, ...
hashArray is local to the function; as soon as the function exits, hashArray is no longer valid, so you'll be returning a pointer to garbage.
A VLA is not the right tool to use here. I suggest making the following changes:
TblPTR *createHashArray(size) // return a pointer to TblPTR
{
...
TblPTR *hashArray = malloc(sizeof *hashArray * size);
if (hashArray)
{
// initialize hash array as you're currently doing
}
return hashArray;
}
Note that you'll have to free() the array at some point later in your code.

Resources