C segmentation fault when using pointer to pointers to struct - c

I have defined a structure StructA and function StructA createStructA(...) that creates and returns a new StructA. I want to have a function foo() that will explicitly return int error code as well as a new StructA that I want to use outside foo(). So it seems I need pointers to pointers:
int foo(StructA **pA) {
// Allocate some memory:
*pA = malloc(sizeof(StructA)); // (Editor's note: don't cast the return of malloc.)
// check that malloc() didn't error.
assert(*pA);
// Fill out a new StructA with createStructA():
StructA a = createStructA(...);
// return
*pA = &a;
return 0;
}
Why does this code exit with segmentation fault? It appears it is due to malloc as if I comment out all other lines except for malloc line it still breaks with segfault
As the code above may seem unclear, here is MCVE of my problem:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int x;
int y;
} A;
typedef struct {
A a;
int z;
} B;
A makeA() {
return (A) {.x = 1, .y = 2};
}
B makeB(A a1) {
return (B) {.a = a1, .z = 3};
}
void parseA(A **ppa) {
*ppa = malloc(sizeof(A)); // crashes with segfault here
**ppa = makeA();
}
void parseB(B **ppb) {
A **ppa;
parseA(ppa);
// todo make B .. but it's already crashing
}
int main() {
B **ppb;
parseB(ppb);
return 0;
}

*pA = &a set the *pA pointing to a local variable within function foo. When function returns, local variable is out of scope, therefore *pA becomes invalid.
Edit:
Just read your new code. In this line, *ppa = malloc(sizeof(A)); // crashes with segfault here, ppa is not a valid pointer yet, you cannot dereference it by *ppa. Need to do ppa = (A**)malloc(sizeof(A*));first.
Actually, I make a guess here, this is want you want:
void parseA(A **ppa) {
*ppa = (A*)malloc(sizeof(A));
// todo make A, e.g. ppa->x = 1;
}
void parseB(B **ppb) {
A *ppa = NULL;
parseA(&ppa);
// ppa is a valid point now, you can do, e.g. ppa->y=1;
// todo make B
}

In addition to the other corrections, if you will need ppa back in the calling function main, you have no way of returning a value to main. While there is exercise value in what you are doing, your actual goal is anything but clear. It is somewhat of an XY problem, see: What is the XY problem?.
That said, reading between the lines, and to make ppa available back in main, your parseB would have to somehow return a value. You could do so by changing the type to A *parseB (B **ppb).
Further, you seem to have a bit of confusion in whether to declare ppa and ppb as pointers or pointer-to-pointer-to-type. Given your initialization and use, it appears you want a pointer to both ppa and ppb. You would then pass the address of each to the functions parseB and parseA and dereference accordingly to allocate storage for their contents. Doing so, you could craft a parseB similar to:
A *parseB (B **ppb)
{
A *ppa = NULL;
void *tmp = realloc (*ppb, sizeof **ppb);
if (!tmp) {
fprintf (stderr, "error: realloc ppb.\n");
return NULL;
}
*ppb = tmp;
parseA (&ppa);
if (ppa)
**ppb = makeB (*ppa);
return ppa;
}
note: realloc is used for the allocation, because you have no control over whether *ppb has been previously allocated within parseB itself (you do have control over what you send to parseA from parseB so malloc is fine in parseA)
To start this daisy-chain of allocation and assignment of values, your main could be written similar to:
int main ()
{
B *ppb = NULL;
A *ppa = parseB (&ppb);
if (ppa && ppb) {
printf ("ppa->x: %d\nppa->y: %d\n\n"
"ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);
free (ppa);
free (ppb);
}
return 0;
}
Granted, I do not have a clear picture of what you are ultimately attempting to accomplish. So to make use of the values you assign, the pointer level of indirection at the declaration was reduced to make sense of what it looked like you were trying to do. That said, and putting all the pieces together, you could do something similar to the following:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int x;
int y;
} A;
typedef struct {
A a;
int z;
} B;
A makeA ()
{
return (A) {.x = 1,.y = 2};
}
B makeB (A a1)
{
return (B) {.a = a1,.z = 3};
}
void parseA (A **ppa)
{
*ppa = malloc (sizeof (A));
**ppa = makeA ();
}
A *parseB (B **ppb)
{
A *ppa = NULL;
void *tmp = realloc (*ppb, sizeof **ppb);
if (!tmp) {
fprintf (stderr, "error: realloc ppb.\n");
return NULL;
}
*ppb = tmp;
parseA (&ppa);
if (ppa)
**ppb = makeB (*ppa);
return ppa;
}
int main ()
{
B *ppb = NULL;
A *ppa = parseB (&ppb);
if (ppa && ppb) {
printf ("ppa->x: %d\nppa->y: %d\n\n"
"ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);
free (ppa); /* if you allocate it, it is up to you to free it */
free (ppb);
}
return 0;
}
Example Use/Output
$ ./bin/structptrissue
ppa->x: 1
ppa->y: 2
ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3
Memory Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/structptrissue
==19399== Memcheck, a memory error detector
==19399== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19399== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==19399== Command: ./bin/structptrissue
==19399==
ppa->x: 1
ppa->y: 2
ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3
==19399==
==19399== HEAP SUMMARY:
==19399== in use at exit: 0 bytes in 0 blocks
==19399== total heap usage: 2 allocs, 2 frees, 20 bytes allocated
==19399==
==19399== All heap blocks were freed -- no leaks are possible
==19399==
==19399== For counts of detected and suppressed errors, rerun with: -v
==19399== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.

Related

Can't find valgrind error on program which terminates and returns the right output correctly

Even though the program terminates correctly and gives me the right output, and there are no memory leaks, valgrind gives me some errors of this kind:
Invalid read of size 1
==910== at 0x108DD4: fnv_hash_function (user.c:24)
==910== by 0x108E17: hash (user.c:29)
==910== by 0x109A50: icl_hash_find (icl_hash.c:114)
==910== by 0x1094DB: db_request (user.c:197)
==910== by 0x108D2E: main (tuser.c:65)
==910== Address 0x5416f50 is 0 bytes inside a block of size 15 free'd
==910== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==910== by 0x109152: freeKey (user.c:138)
==910== by 0x109CF2: icl_hash_delete (icl_hash.c:192)
==910== by 0x109796: db_request (user.c:222)
==910== by 0x108CF8: main (tuser.c:59)
==910== Block was alloc'd at
==910== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==910== by 0x108BDC: main (tuser.c:35)
The hash and fnv_hash_function are defined in this way
static inline unsigned int fnv_hash_function( void *key, int len ) {
unsigned char *p = (unsigned char*)key;
unsigned int h = 2166136261u;
int i;
for ( i = 0; i < len; i++ )
h = ( h * 16777619 ) ^ p[i]; //this is the line 24
return h;
}
unsigned int hash(void *key){
return fnv_hash_function(key, strlen(key));
}
I guess the problem is the ^ operator, but I can't figure out what the problem is, since the program terminates with the right output and without segmentation faults.
The icl_hash_find is not a function written by me, but is inside a library I'm using and is defined in this way
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(curr->data);
return NULL;
}
I tried valgrind on the test suite of that library and no errors were found so I doubt the problem is there.
EDIT:
The key is allocated in this for loop:
char * s; //string used as key
for(int i = 0; i < N; i++){
s = (char *)malloc(NAMELEN * sizeof(char));
sprintf(s, "Utente %d", i);
u = create_user( s , i);
if(!db_request(db, s, u, PUT)){
perror("problema PUT");
exit(EXIT_FAILURE);
}
.
.
.
EDIT 2: Here's the body of db_request:
bool db_request(userbase_t *db, char * key, user_t * u, dbop_t op ){
if(db==NULL || key == NULL ||(op!=DELETE && u==NULL)){
errno = EINVAL;
return false;
}
int lock_index; //indice del lock del bucket
switch(op){
//implementazione PUT
case PUT :
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index])
errno = 0;
if(icl_hash_insert(db->table, key, (void *) u)==NULL){
RWUNLOCK(&db->locks[lock_index])
//la chiave e' gia' associata ad un utente
if(errno == EINVAL){
perror("key gia' presente");
}
return false;
}
RWUNLOCK(&db->locks[lock_index])
return true;
//implementazione GET
case GET :
lock_index = db -> table -> hash_function(key) % db->nlocks;
RLOCK(&db->locks[lock_index])
u = icl_hash_find(db->table, (void *)key );
RWUNLOCK(&db->locks[lock_index]);
return true;
//implementazione update
case UPDATE :
//elimina il vecchio e aggiunge il nuovo
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index]);
if(icl_hash_delete(db->table, key, freeKey, freeUser)){
perror("problema UPDATE (icl_hash_delete) ");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
if (icl_hash_insert(db->table, key, (void *) u)==NULL){
perror("problema UPDATE (icl_hash_insert)");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
case DELETE :
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index]);
if(icl_hash_delete(db->table, key, freeKey, freeUser)){
perror("problema DELETE");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
RWUNLOCK(&db->locks[lock_index]);
return true;
//mai raggiunto
default :
errno = EINVAL;
perror("problema switch op");
return false;
}}
But I can't find the problem, I'm starting to think the problem is in the icl_hash lib.
The problem happens when I'm calling the GET on an element I've just DELETED in the test function.
if(!db_request(db, s , u ,DELETE)){
perror("problema DELETE");
exit(EXIT_FAILURE);
};
//provo a ottenerlo di nuovo
//The error happens here
if(!db_request(db, s , u ,GET)){
perror("GET");
exit(EXIT_FAILURE);
};
The only thing the get does is call this function:
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(curr->data);
return NULL;
}
Your invalid access is to memory that is already freed:
Invalid read of size 1
==910== at 0x108DD4: fnv_hash_function (user.c:24)
==910== by 0x108E17: hash (user.c:29)
==910== by 0x109A50: icl_hash_find (icl_hash.c:114)
==910== by 0x1094DB: db_request (user.c:197)
==910== by 0x108D2E: main (tuser.c:65)
==910== Address 0x5416f50 is 0 bytes inside a block of size 15 free'd
==910== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==910== by 0x109152: freeKey (user.c:138)
==910== by 0x109CF2: icl_hash_delete (icl_hash.c:192)
==910== by 0x109796: db_request (user.c:222)
==910== by 0x108CF8: main (tuser.c:59)
==910== Block was alloc'd at
==910== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==910== by 0x108BDC: main (tuser.c:35)
The block was freed in a call to icl_hash_delete() made at line 222 in the function db_request() in the file user.c. The invalid access was made in a call to icl_hash_find() at line 197 in db_request() in user.c. You say that the icl_hash* code is provided to you.
Without the body of the function db_request() is is difficult to be sure what's going on, but there are at least a couple of possibilities.
You've got a dangling pointer to the entry that was deleted, and you should not still be using that.
The code in the icl_hash* functions is mishandling data after a hash record is deleted.
If the provider of the icl_hash.c function is reasonably reliable, it is sensible to assume that the problem is in your code in db_request(). Look hard at lines 197 and 222 in particular, and the variables (pointers) passed to the icl_hash_find() and icl_hash_delete() functions. Look again at the manual page for those functions to see what the rules are.
If you're not sure about the quality of the code in icl_hash.c, you should create yourself a smaller MCVE that creates a hash table, adds some rows, finds some rows, deletes some entries, and does some more finding. This will help you identify whether there's a problem in your code or in the icl_hash.c code.
Since the memory was allocated in main() rather than db_request(), you might have to review what you're doing at that level, but my guess is that you passed that pointer to db_request() and handed ownership of it to the hash table when you added an entry, and the specification of icl_hash_delete() says it will free the memory you handed to the hash table, and you are accidentally still holding a pointer to the now freed memory (the argument to the db_request() function). You have to be very careful to ensure you know who owns what memory — and when that memory has been released.
Valgrind tells you that you have a problem in fnv_hash_function function. In this function you access memory after it has been freed (deallocated) in freeKey. It even tells you that you access it exactly at the beginning of that block of memory. You allocated that memory in main (tuser.c:35). Your program works by accident. It will continue to work as long as the block of memory in question will not end up at the beginning of a memory page and it will be the last block freed on that page - then the page will be (probably - depending on the allocator strategy) unmapped from your process space. After that unmapping if you access it (like in fnv_hash_function) your program will crash exactly at the moment you try access it.
When that block could end up as the first block on the page and be the last one to be freed ? - difficult to say it may happen after any changes that you make to your source code or underlying libraries (including system libraries that you don't control).

Invalid write of size 8 after a malloc

I am currently working on a project for my school and I am having issues with my code. The purpose of the programm is to implement a plugin manager that search in a directory all "*_plugin.so" file and add a plugin descriptor into a simple linked list.
The C code :
//struct of a single node
typedef
struct _chainon_ {
plugin_descriptor * desc;
struct _chainon_ * next;
} Chainon;
// manager that contains sentry node & number of plugins contained by the list
struct plugin_manager_t {
int nbElts;
Chainon * sentinel;
};
typedef
struct {
const char * m_name; // nom du filtre
const char * m_description; // description de l'effet du filtre
filter_function m_filtre; // fonction de réalisation du filtre
} plugin_descriptor;
Now the register_plugin function, it is called while the programm find a new plugin in the directory, it calls an init_ function that call register_plugin :
void
init_(plugin_manager * pm)
{
register_plugin(pm,
"null_filter",
"Exemple de filtre inutile",
null_filter);
}
and then it is supposed to add the new plug to the list :
void
register_plugin(plugin_manager * pm,
const char filter_name[],
const char filter_description[],
filter_function the_filter)
{
Chainon * n = (Chainon *)malloc(sizeof(Chainon)); //new node that i want to add to the linked list
n->desc = NULL;
n->next = NULL;
n->desc->m_name = filter_name;
n->desc->m_description = filter_description;
n->desc->m_filtre = the_filter;
Chainon * current = pm->sentinel;
for(int i=0;i<pm->nbElts;i++){
current=current->next;
i++;
}
current->next = n;
}
And that is what I am getting with valgrind while I execute this programm :
> ==7022== Invalid write of size 8
> ==7022== at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022== by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022== by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022== by 0x401187: main (main.cc:17)
> ==7022== Address 0x0 is not stack'd, malloc'd or (recently) free'd
> ==7022==
> ==7022==
> ==7022== Process terminating with default action of signal 11 (SIGSEGV)
> ==7022== Access not within mapped region at address 0x0
> ==7022== at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022== by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022== by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022== by 0x401187: main (main.cc:17)
> ==7022== If you believe this happened as a result of a stack
> ==7022== overflow in your program's main thread (unlikely but
> ==7022== possible), you can try to increase the size of the
> ==7022== main thread stack using the --main-stacksize= flag.
> ==7022== The main thread stack size used in this run was 8388608.
I am novice at C programming
But I do not understand why I could not initialize "n->desc->name" since I allocated the memory with malloc and then initialized everything to NULL ?
Any help would be appreciate !
Thank you
Your code has several problems, some of them are minor problems and others are causing the posted valgrind output,
Is not really a problem, it's just that you don't need to cast the return value of malloc()
Chainon *n = malloc(sizeof(Chainon));
is ok, no need for the cast.
You need to check that malloc() succeeded, not just assume that it did, under normal situations it will not fail, but in case of failure your program does not handle that, and in case it has some sensitive data that needs to be stored in the hard drive or any other situation where a clean exit is needed, you will cause a lot of problems to the program users, so you should ensure that your program exits cleanly, hence checking the return value of malloc() is a very good thing to do, just check against NULL right after every call to malloc() and handle that according to the situation where the failure occurs.
You don't allocate space for your struct members, every pointer must point to valid memory before dereferencing it, so you must ensure that it does point to valid memory, uninitialized pointers can't be checked so in cases where you are going to initialize the pointer after a possible check, initialize it to NULL.
You do that in one case, but then you dereference the NULL pointer, which is undefined behavior.
Using all the recommendations above, your function has to be re-written like this*
void
register_plugin(plugin_manager * pm,
const char *const filter_name,
const char *const filter_description,
filter_function the_filter)
{
Chainon *chainon;
plugin_descriptor *descriptor;
Chainon *current
int i;
if (pm == NULL)
return;
chainon = malloc(sizeof(*chainon));
if (chainon == NULL)
return;
chainon->next = NULL;
descriptor = malloc(sizeof(*descriptor));
if (descriptor == NULL)
{
free(chainon);
return;
}
chainon->desc = descriptor;
descriptor->m_name = filter_name;
descriptor->m_description = filter_description;
descripotor->m_filtre = the_filter;
current = pm->sentinel;
if (current == NULL)
return;
for(i = 0 ; ((i < pm->nbElts) && (current->next != NULL)) ; ++i)
current = current->next;
current->next = chainon;
}
*Some of the things I changed are not really necessary. I just think it's better that way.

Access violation of dynamic array for hashmap

I am having an issue with the table of a little hashmap I am trying to implement.
map.h
typedef struct Map Map;
Map *map_create();
int map_set(Map *map, char *key, void *val);
map.c
const int MAP_INITIAL_SIZE = 100;
typedef struct MapPair MapPair;
struct MapPair
{
char *key;
void *val;
};
struct Map
{
MapPair **table;
int count;
int limit;
};
Map *map_create(void)
{
Map *map = (Map*)malloc(sizeof(Map));
if (!map) return NULL;
map->table = (MapPair**)malloc(MAP_INITIAL_SIZE * sizeof(MapPair));
if (!map->table)
{
free(map);
return NULL;
}
map->count = 0;
map->limit = MAP_INITIAL_SIZE;
return map;
}
void add(MapPair **context, int start, MapPair *pair, int limit)
{
int i = start;
while (context[i] != NULL && strcmp(context[i]->key, pair->key) != 0) // crashing here
{
i++;
if (i == limit) i = 0;
}
context[i] = pair;
}
int map_set(Map *map, char *key, void *val)
{
if (map->count >= map->limit / 2)
{
if (!expand(map)) return 0;
}
MapPair *pair = (MapPair*)malloc(sizeof(MapPair));
if (!pair) return 0;
pair->key = key;
pair->val = val;
add(map->table, hash(key, map->limit), pair, map->limit);
++map->count;
return 1;
}
I was originally developing in pelles c but moved to vs2013 for the debugger when I was experiencing problems. Then in vs2013 the program would crash at the add function but not in pelles c. I am assuming it has something to do with my dynamic array that I plan to be able to expand later.
Can anybody tell me why the program seems to crash when I try to access an index of the dynamic array?
In add function you are checking the table, until you reach the NULL pointer:
while (context[i] != N ...
But when you allocate this table you never set any of those pointers to NULL:
map->table = (MapPair**)malloc(MAP_INITIAL_SIZE * sizeof(MapPair));
You should set them to NULL:
for( size_t i = 0 ; i < MAP_INITIAL_SIZE ; i++ )
map->table[i] = NULL ;
Otherwise you will go out of bounds of that array.
I didn't know Visual could compile pure C projects ! Anyway, your crash is caused by a magic string : http://en.wikipedia.org/wiki/Magic_number_(programming)
* 0xABABABAB : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory
* 0xABADCAFE : A startup to this value to initialize all free memory to catch errant pointers
* 0xBAADF00D : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory
* 0xBADCAB1E : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger
* 0xBEEFCACE : Used by Microsoft .NET as a magic number in resource files
* 0xCCCCCCCC : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory
* 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory
* 0xDEADDEAD : A Microsoft Windows STOP Error code used when the user manually initiates the crash.
* 0xFDFDFDFD : Used by Microsoft's C++ debugging heap to mark "no man's land" guard bytes before and after allocated heap memory
* 0xFEEEFEEE : Used by Microsoft's HeapFree() to mark freed heap memory
(SO source : In Visual Studio C++, what are the memory allocation representations?)
Unlike GCC (or pelles I imagine), Visual Studio set uninitialized heap array pointers as 0xCDCDCDCD, not NULL. So your check of context[i] != NULL returns true even though context is not initialized.
... And that's why explicit is always better than implicit.

glibc detected - double free or corruption (!prev)

I'm getting the error you may see in the title, and I can't figure out why.
The code:
#include <cstdlib>
#include <cstdio>
struct CData {
int* num;
char* adr;
char* ph;
void (*init)(CData* owner);
void (*del)(CData* owner);
char* (*getAdr)(CData* owner);
void (*setAdr)(CData* owner, char* adr);
};
void CData_init(CData* owner) {
owner->num = (int*)malloc(sizeof(int));
owner->adr = (char*)malloc(sizeof(char)*255);
owner->ph = (char*)malloc(sizeof(char)*255);
}
void CData_del(CData* owner) {
free(owner->num);
free(owner->adr);
free(owner->ph);
}
char* CData_getAdr(CData* owner) {
return owner->adr;
}
void CData_setAdr(CData* owner, char* adr) {
owner->adr = adr;
}
int main() {
CData* data = (CData*)malloc(sizeof(CData));
data->init = CData_init;
data->del = CData_del;
data->getAdr = CData_getAdr;
data->setAdr = CData_setAdr;
data->init(data);
data->setAdr(data, "asdasd");
printf("%d", data->getAdr(data));
data->del(data);
free(data);
return 0;
}
So I think the error is caused by the char* manipulations but I don't know why.
What I want to do is I want it to be possible to pass a string as a parameter to data->setAdr and I want it to be assigned to the variable afterwards.
Compiling line:
gcc -o test main.cpp
data->setAdr(data, "asdasd"); is problematic.
You are setting the address of a memory block that is not allocated by malloc and later trying to free it with free. Freeing such memory blocks (not allocated by malloc) except NULL pointer lead to undefined behavior.
This is also leaking atleast 255 bytes of memory in your case. valgrind can help you understand better in this case.
Changing following function should fix this (Rename it appropriately)
void CData_setAdr(CData* owner, char* adr) {
strcpy(owner->adr, adr); /* include cstring */
}
The problem is here:
data->setAdr(data, "asdasd");
Your implementation is :
void CData_setAdr(CData* owner, char* adr) {
owner->adr = adr;
}
So, you overwrite the address of a previously-malloc()ed memory with a pointer to a constant string, so when you do data->del(data);, glibc warns that you are freeing memory that was not allocated, plus the previously allocated memory is lost. Try instead:
void CData_setAdr(CData* owner, char* adr) {
strcpy(owner->adr, adr);
}
Remember to add suitable error-checking, etc!

Cant copy a string to a string in a struct ( C )

I am trying to copy some strings to strings in a struct using strcpy. I am posting the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef struct floating_point{
char sign[2];
char exponent[9];
char fraction[24];
}FLOATING_POINT;
FLOATING_POINT stringToFloatingPoint(char* str){
struct floating_point fp;
char *integer_str,*fraction_str,*integer_bin,*fraction_bin,*sign;
sign=(char*)malloc(2*sizeof(char));
int i=1,integer=0,fraction=0,comma=0,remainder=0,size=0;
double fraction_double;
//str=(char*)malloc(200*sizeof(char));
//str="108,53";
char * pch=(char*)malloc((strlen(str)+1)*sizeof(char));
pch=strchr(str,',');
if(pch==NULL){
pch=str+strlen(str);
}
comma=pch-str;
integer_str=(char*)malloc((comma+1)*sizeof(char));
strncpy(integer_str,str,comma);
integer_str[comma]='\0',
integer=atoi(integer_str);
fraction_str=(char*)malloc((strlen(str)-comma+2)*sizeof(char));
strncpy(fraction_str,str+comma+1,strlen(str)-1);
fraction_str[strlen(str)-comma]='\0';
fraction=atoi(fraction_str);
printf("%d",fraction);
printf("%s",fraction_str);
if(integer<0){
strcpy(sign,"1");
integer=-1*integer;
}
else{
strcpy(sign,"0");
}
size=(int)(log(integer)/log(2))+2;
integer_bin=(char*)malloc(size*sizeof(char));
while(integer>0){
remainder=fmod(integer,2);
integer=integer/2;
*(integer_bin+size-i-1)=(char)(remainder+48);
i++;
}
*(integer_bin+size-i-1)=(char)(integer+48);
*(integer_bin+size-1)='\0';
printf("%s\n",integer_bin);
fraction_bin=(char*)malloc(24*sizeof(char));
fraction_double=atof(fraction_str);
fraction_double=fraction_double/(pow(10,strlen(fraction_str)));
printf("frac= %f",fraction_double);
i=0;
while((i<23)&&fraction_double!=0){
fraction_double=2*fraction_double;
if(fraction_double<1){
*(fraction_bin+i)='0';
}
else{
fraction_double=fraction_double-1;
*(fraction_bin+i)='1';
}
i++;
}
*(fraction_bin+i)='\0';
printf("\n%s",integer_bin);
printf("\n%s",fraction_bin);
size=strlen(integer_bin);
for(i=0;i<strlen(fraction_bin)-(size-1);i++){
*(fraction_bin+strlen(fraction_bin)-1-i)=*(fraction_bin+strlen(fraction_bin)-size-i);
}
for(i=1;i<size;i++){
*(fraction_bin+i-1)=*(integer_bin+i);
}
printf("\n%s",fraction_bin);
free(integer_bin);
integer_bin=(char*)malloc(9*sizeof(char));
strcpy(integer_bin,"00000000");
printf("integer_bin %s",integer_bin);
integer=127+size-1;
i=1;
while(integer>0){
remainder=fmod(integer,2);
integer=integer/2;
*(integer_bin+8-i)=(char)(remainder+48);
i++;
}
*(integer_bin+8-i)=(char)(integer+48);
*(integer_bin+8)='\0';
printf("\n\n%s %s %s",sign,integer_bin,fraction_bin);
strcpy(fp.exponent,integer_bin);
strcpy(fp.sign,sign);
strcpy(fp.fraction,fraction_bin);
free(integer_bin);
free(integer_str);
free(fraction_bin);
free(fraction_str);
free(sign);
free(pch);
}
int main()
{
struct floating_point fp=stringToFloatingPoint("108,53");
printf("\n\n%s %s %s",fp.sign,fp.exponent,fp.fraction);
}
Everything works well till the strcpy part.
printf("\n\n%s %s %s",sign,integer_bin,fraction_bin);
This printf works well. And the size of my strings are equal to the ones in the struct. You can see how much memory I have allocated using malloc.
I dont get an error but when I print the values in my main funciton they are not correct.
What can the problem be?
Your function is missing its return statement.
You should pay more attention to the compiler warnings, or turn more warnings on, or get a better compiler.
You missed a return in the function stringToFloatingPoint... at least this one is a problem...
Add
Just to let you know, executing gcc -std=c99 -pedantic -Wall ./boh.c -lm or similar for your compiler, would have say:
./boh.c: In function ‘stringToFloatingPoint’:
./boh.c:105: warning: control reaches end of non-void function
Valgrind would say:
==6480== HEAP SUMMARY:
==6480== in use at exit: 7 bytes in 1 blocks
==6480== total heap usage: 7 allocs, 7 frees, 59 bytes allocated
==6480==
==6480== LEAK SUMMARY:
==6480== definitely lost: 7 bytes in 1 blocks
You mostly can avoid allocation, especially of two chars or so...
Moreover, running it will give a problem (double free or corruption)...
Likely the leak is here:
char * pch=(char*)malloc((strlen(str)+1)*sizeof(char));
pch=strchr(str,',');
if(pch==NULL){
pch=str+strlen(str);
}
Here you are allocating memory, then you search for a char and trash the pointer to the allocated memory... If you then will try to free(pch), you will cause a problem...
Your function is specified as returning a FLOATING_POINT structure:
FLOATING_POINT stringToFloatingPoint(char* str)
But nowhere in the function is there a return statement.

Resources