Storing void pointers in a struct - c

I'm getting segmentation fault on code that is trying to initialize a struct of pointers to 0mq context and socket. The commented out code in the main method works, but it's only using local variables. I would like to initialize them and pass them around in a struct, but my google foo is failing me on how to do this properly.
#include "zhelpers.h"
#include <stdio.h>
#include <stdlib.h>
#include <zmq.h>
struct publisher{
void *handle;
void *context;
};
void init_publisher(struct publisher *p);
void destroy_publisher(struct publisher *p);
void publish(struct publisher *p,char *msg);
void init_publisher(struct publisher *p)
{
p = (struct publisher *)malloc(sizeof(struct publisher));
p->context = malloc(sizeof(void *));
p->handle = malloc(sizeof(void *));
void *context = zmq_ctx_new();
void *handle = zmq_socket(context,ZMQ_PUB);
zmq_bind(handle, "tcp://*:5556");
zmq_bind(handle, "ipc://feed.ipc");
p->context = context;
p->handle = handle;
}
void destroy_publisher(struct publisher *p)
{
zmq_close(p->handle);
zmq_ctx_destroy(p->context);
free(p->handle);
free(p->context);
free(p);
}
void publish(struct publisher *p,char *msg)
{
s_send(p->handle, msg);
}
int main(void)
{
/**
void *context = zmq_ctx_new();
void *publisher = zmq_socket(context, ZMQ_PUB);
int rc = zmq_bind(publisher, "tcp://*:5556");
assert(rc == 0);
rc = zmq_bind(publisher, "ipc://weather.ipc");
assert(rc == 0);
printf("Started Weather Server...\n");
srandom((unsigned) time (NULL));
int zipcode, temperature, relhumidity;
zipcode = randof(100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
char update[20];
sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity);
s_send(publisher, update);
zmq_close(publisher);
zmq_ctx_destroy(context);
*/
struct publisher *p;
init_publisher(p);
printf("Setup pub\n");
srandom((unsigned) time (NULL));
int zipcode, temperature, relhumidity;
zipcode = randof(100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
char update[20];
sprintf(update, "%05d %d %d", zipcode, temperature, relhumidity);
publish(p,update);
printf("Published Message\n");
destroy_publisher(p);
printf("Destroyed publisher\n");
return 0;
}

There appears to be nothing in this code that would make it crash. (Assuming you know how all your zmq_... stuff works.)
It would have helped if you told us precisely where the error occurs, but my guess would be that the error occurs outside of this code.
You see, you are passing struct publisher *p to your init_publisher() function, but then you are allocating memory for p inside that method, (which makes passing p pointless,) and then you are not returning p. As a result, the code that calls init_publisher() probably expects p to be initialized, but it is not. The memory pointed by p is just allocated and leaked locally within your init_publisher() function.
So, instead of passing p, just have the function declare it and return it.
Alternatively, if the caller has already allocated p, then do not allocate it all over again from within init_publisher().
Please also note that the statements p->context = malloc(sizeof(void *)); are unnecessary and they are leaking small amounts of memory, because you proceed to overwrite these struct members.

The problem is that the passed pointer and the pointer you malloc()ed are not the same. The passed pointer contains the same address of your original pointer, presumably an invalid address, but the addresses of the poninters them selves are different because in c you can only pass a variable by value and hence, the pointer is copied.
That means that when you reassign p inside the function, the p from outside the function is unaltered. It would be different if it was allocated outside and you just use the function to access it's members.
You also don't need to malloc() every pointer you want to use, the thing is that it must point to a valid address before dereferencing it. When you want to request new uninitialized memory then you use malloc() otherwise you just make the pointer point to a valid address so that dereferencing it is defined, one example of using a pointer without malloc()ing it is
int *pointer;
int value;
value = 4;
pointer = &value; // Now `pointer' points to `value's` address
*pointer = 3;
printf("%d\n", value);
One way to write the function would be
int
init_publisher(struct publisher **pp)
{
struct publisher *p;
*pp = malloc(sizeof(struct publisher));
if (*pp == NULL)
return -1;
p = *pp;
p->context = zmq_ctx_new();
p->handle = zmq_socket(context,ZMQ_PUB);
if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */
{
zmq_bind(p->handle, "tcp://*:5556");
zmq_bind(p->handle, "ipc://feed.ipc");
}
return 0;
}
and then you could use it like this
struct publisher *p;
if (init_publisher(&p) != 0)
do_something_there_was_an_error();
/* Continue using `p' */
Note that the funcion is returning a value indicating whether allocations succeeded or not. Normally malloc() will not fail, but that doesn't mean that you should ignore the possible failure.
What I mean when I say if you allocate p first, is that if you instead do this
struct publisher *p;
p = malloc(sizeof(*p));
if (p == NULL)
return handle_error();
init_publisher(p);
then init_publisher() could be
void
init_publisher(struct publisher *pp)
{
void *context;
void *handle;
p->context = zmq_ctx_new();
p->handle = zmq_socket(context,ZMQ_PUB);
if (p->handle != NULL) /* Just in case, do not dereference a NULL pointer */
{
zmq_bind(p->handle, "tcp://*:5556");
zmq_bind(p->handle, "ipc://feed.ipc");
}
}
which is probably what you was trying to do.

Related

Malloc within function not changing pointer value

So when I pass a data type like a struct to assign some memory to it I find that the pointer doesn't change within the main scope. This further becomes a problem when I try to free the memory but obviously if its using the original pointer it will be pointing at the stack address.
void allocate(int *value){
value = malloc(10 * sizeof(int));
}
int main(){
int val2;
allocate(&val2);
free(&val2);
return 0;
}
I can fix this by using a double pointer to be passed into the allocate function but some course work I'm doing requires to only pass a pointer and I cant get it to update the pointer when it returns to main. I have looked around for a while but cant find a straight forward answer, I feel like my coursework is wrong but that might be my lack of understanding.
The requirement to "only pass a pointer" seems contrived, and you could argue that a pointer to pointer (not a "double pointer") is a pointer, but perhaps you could use void * to punch a hole in the type system. Or use a struct:
#include <stdlib.h>
#include <stdio.h>
struct intbuffer {
int *d;
size_t cap;
};
void *
xmalloc(size_t s)
{
void *r = malloc(s);
if( r == NULL ){
perror("malloc");
exit(1);
}
return r;
}
void
allocate(void *p, size_t s)
{
*(int **)p = xmalloc(s * sizeof(int));
}
void
allocate2(struct intbuffer *p)
{
p->d = xmalloc(p->cap * sizeof *p->d);
}
int
main(void)
{
int *val2;
struct intbuffer v;
allocate(&val2, 10);
free(val2);
v.cap = 10; /* Horrible api!! */
allocate2(&v);
free(v.d);
return 0;
}
Note that setting the capacity in the struct prior to making the call to allocate is a violation of many principles of software design, but this whole thing is absurdly contrived due to the bizarre artificial limitations.
There are not enough *'s in each place, but you will have to figure out what that means.
void allocate(int** value){
*value = malloc(10 * sizeof(int));
}
int main(){
int* val2;
allocate(&val2);
free(val2);
return 0;
}

Am I freeing memory properly?

Okay, so I have a homework assignment for a C programming class and I just finished with the output doing what I expected. However, I am still a bit confused on memory allocation and freeing.
Basically what has me question my self is the freeing of the structure memory and the "Change_name" function. In my program I am just taking the new name and setting the value who.name to the new name. But what happens to the "old" name in this scenario? when I call free(who), is the old name being deleted?
any clarification would be appreciated!
code:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
/* complete this function, which initialize the fileds of the struct, and return a pointer to the initialzied struct */
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
(*who).name = name;
(*who).age = age;
(*who).height = height;
(*who).weight = weight;
return who;
}
/* complete this function, which free memory that was allocated for a struct*/
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who);
}
/* complete this function, which print the value of member of struct for the input argument */
void Person_print(struct Person *who)
{
printf("This person have the values of...\n");
printf("name: %s\n", (*who).name);
printf("age: %d\n", (*who).age);
printf("height: %d\n", (*who).height);
printf("weight: %d\n", (*who).weight);
}
/* complete this function, which change the value of filed member of the struct to the value of newName */
void Change_name (struct Person *who, char * newName)
{
(*who).name = newName;
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person *joe = Person_create(
"Joe Alex", 32, 64, 140);
struct Person *frank = Person_create(
"Frank Blank", 20, 72, 180);
// print them out and where they are in memory
printf("Joe is at memory location %p:\n", joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", frank);
Person_print(frank);
// make changes in filed of goe's struct print them again
joe->age += 20;
joe->height -= 2;
joe->weight += 40;
Change_name(joe, "Jack The third Junior Smith Benedickt");
Person_print(joe);
// destroy them both so we clean up
Person_destroy(joe);
Person_destroy(frank);
return 0;
}
Your call to Person_destroy doesn't free any of the names because you're just freeing who. But that's OK because you're also not dynamically allocating any of the names with malloc/strdup/etc...
TL;DR: For your specific example: yes, but there are caveats to what you're doing.
One question that needs addressing WRT change_name is this:
ut what happens to the "old" name in this scenario? when I call free(who), is the old name being deleted?
For reasons that, I hope, will become clear further down, there is no clear answer to this question. Your code assigns a char * blindly. You don't know where that string is stored. If it's a string constant with static storage (either global variable or const char * in main), that old name will remain in memory for as long as your application runs. If it's dynamically allocated, unsetting a pointer doesn't free the memory either. assigning a new pointer can potentially cause you to leak memory. The safest way is to copy the string (strdup), and free the pointer prior to changing the name field.
There's an underlying problem here: You can only free memory in the right way if you allocate it correctly. Strictly speaking, you are doing just that. However, a function that takes a char * shouldn't blindly assign that same pointer. The pointer might be a stack char[] that decayed into a pointer (because it was passed as an argument).
You have no idea where that string was allocated, how, and most importantly: how long the pointer will remain valid. A couple of scenario's where a char * can cause problems:
int main ( void )
{
struct Person *p = foobar();
printf("name => %s?", p->name);
Person_destroy(p);
return 0;
}
struct Person *foobar( void )
{
char bar[] = "this is a local string";
return Person_create(bar, 32, 64, 140);
}
The pointer to bar expires once foobar returns, so this is a problem (stack memory pointers).
A pointer on the heap might suffer from the same problem:
struct Person *foobar( void )
{
const char *x = "Name";
char *bar = strdup(x); // allocates on heap and copies string
// check for null's etc...
struct Person *person = Person_create(bar, 32, 64, 140);
//some more stuff happens, including:
bar = realloc(bar, strlen(x) + 255);
strncat(bar, " has been successfully allocated", 33);
return person;
}
The problem here is that realloc might memmove the original string, and return an entirely new pointer, in which case the name field of the struct will become invalid. If that doesn't happen, person->name now points to Name has been successfully allocated, which is a potential bug.
So I strongly advise you to copy the name string:
// note: const char *name
struct Person *Person_create(const char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof *who); // shorter to write, more reliable
if (who == NULL)
exit(1);// or whatever
who->name = strdup(name); // create copy
//etc...
return who;
}
This means, of course that struct Person will need to free the name pointer:
void Person_destroy(struct Person *who)
{
free(who->name);
free(who);
}
Double indirection is a bit risky a lot of the time, but imagine someone doing something like this:
int main( void )
{
struct Person *p = Person_create("Name", 1, 2, 3);
//do stuff
Person_destroy(p);
// more stuff, eg:
printf("%p\n", (void *)p);
Person_destroy(p);
return 0;
}
This is not good,. p should be null'ed after freeing it. Freeing an invalid pointer is bad, mkay. 2 ways to make this a less common problem:
#define FREE_PERSON(p) do {\
Person_destroy(p);\
p = NULL;\
} while(0);
This macro will always set the person variable to NULL after calling Person_destroy. The downside is: it's a clunky macro, and people can (and will) bypass it.
Change Person_destroy a bit:
void Person_destroy(struct Person **p)
{
if (p == NULL)
return; // this is needed now
struct Person *tmp = *p;
free(tmp->name);
free(tmp);
*p = NULL; // set the pointer itself to NULL
}
This forces people to call Person_destroy with a pointer to their pointer, and automatically sets their pointer to NULL.
Again, good practice requires devs to do this themselves, but it's a trivial change and helps prevent problems over time.
Demo using the double-indirection approach

How can I allocate memory for array inside a function

I am trying to receive a number from the user.
And create an array with that number, but, inside a function.
Here are my few attempts, I get into run time errors.
Help is very much appreciated.
#include <stdio.h>
#include <stdlib.h>
int* Init(int* p, int num);
int main() {
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
//for (i = 0; i < num; i++)
//{
// scanf("%d", &p[i]);
//}
free(p);
}
int* Init(int* p, int num)
{
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp)
{
printf("Cannot allocate memory\n");
return;
}
p = pp;
free(pp);
}
You have done well upto the point you understood you need to pass a pointer to pointer. But your function signature doesn't take an int **. Either you pass a pointer to pointer and store the allocated memory in it:
void Init(int **pp, int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
*pp = p;
}
And check if the Init() returns a proper pointer:
Init(&p, num);
if(p == NULL) {
/*Memory allocation failed */
}
Or allocate memory and return the pointer:
int* Init(int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
return p;
}
and from main() call as:
int * p = Init(num);
if(p == NULL) {
/*Memory allocation failed */
}
Change the prototype of Init() accordingly.
In any case, you must not free() the pointer in Init(). That just de-allocates memory immediately and you'll be left with a dangling pointer.
And you need to free() in the main() after you are done with it.
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp) /* pp is used uninitialized at this point */
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
free(p); /* p is used uninitialized at this point */
If you want to allocate space for a pointer to int inside another function, you need to pass a pointer to pointer:
...
Init(&p, num);
...
int Init(int **pp, int num)
{
*pp = malloc(num * sizeof(int));
...
First you need to fix the prototype of your function. It should be
int* Init(int** p, int num);
Then fix the function definition
int* Init(int** p, int num)
{
//int *pp; // You don not need this variable
*p = malloc(num*sizeof(int)); // Allocate memory
if (!*p)
{
printf("Cannot allocate memory\n");
return NULL; // Return a NULL pointer
}
return *p;
}
Some typos in your code,
p = (int *)malloc(num * sizeof(int));
should be
pp = (int *)...
Your free(pp); is what is causing it to not work chiefly, you do not want to call that or the memory you allocated will not be saved. Also the memory of pp is essentially "lost" at the end of the function call as method parameter to Init p is a value copy not exact reference to main's version of p, thus when Init returns, the changes to p are 'lost'.
simply do: p = Init(); and in init return pp;
Exp:
This line p = pp, sets variable p to point to the memory allocated by pp, thus a free of pp is a free to p as well.
I am not sure if returning an address to memory is always considered good practice, as you have to ensure it is freed, but for your program it would work.
It's very important to know that your function doesn't modify your pointer (*p),The **p is lost And *p doesn't have a valid and known memory address in the Main function.
To allocate the memory safely I suggest these two functions.
void init(int **p,int number){
*p = malloc(number*sizeof(int));
}
If you want that your function returns the pointer allocated you can do this:
int* init(int number){
int* p = malloc(number*sizeof(int));
return p;
}

odd program behavior after adding one instruction in C

Actually, I have asked another question with the same code, but this is very different.
I have this code below that displays a very annoying behavior. I've included as much comment in the code as I can so that you can have an idea of what's going on.
#include <stdio.h>
#include <stdlib.h>
/* This is a struct describing properties of an element */
struct element{
int age;
char* name;
};
/* This struct contains a pointer to a pointer on a element "struct element" */
struct person{
struct element** p;
size_t size;
unsigned int id;
};
/* This function initializes a struct person by allocating memory for it */
struct person* init(int _size)
{
if(_size == 0)
{
printf("You gonna have to make some choices \n");
exit(1);
}
struct person* sample = (struct person* )malloc(_size*sizeof(struct person));
sample->p = (struct element** ) malloc(_size*sizeof(struct element*));
sample->id = 0;
sample->size = _size;
return sample;
}
/* use this function to insert a new element in the struct */
void insert(struct person* sample, char* _name, int _age)
{
if (sample->id >= sample->size) {
sample->p = (struct element** ) realloc(sample->p, (sample->size*2) * sizeof(struct element*));
if(sample->p == NULL){
printf("Get a new RAM buddy \n");
exit(1);
}
}
sample->p[sample->id]->name = _name;
sample->p[sample->id]->age = _age; /* of course, this will cause trouble too because it has the same construct as the previous one */
sample->id++;
}
/* main entry */
int main(int argc, char** argv)
{
int i = 0;
struct person* student = init(10); /* Allocating space for 10 students */
insert(student, "baby", 2);
insert(student, "dady", 33);
/* if you remove this line, the program runs, but GDB will signal a segmentation fault. If you keep it, the program will freeze and GDB will behave as expected */
/* I don't understand why this is happening!!!??? */
insert(student, "grandma", 63);
printf("Your name is %s and your age is %d \n", student->p[1]->name, student->p[1]->age);
/* When you only insert two elements, use the results here to match with GDB's results*/
printf("student->p: %p \n", &student->p);
printf("student->p[0]: %p \n", &student->p[0]);
printf("student->p[1]: %p \n", &student->p[1]);
printf("student->p[0]->age: %p \n", &student->p[0]->age);
printf("student->p[0]->name: %p \n", &student->p[0]->name);
/* Won't work for more than two elements inserted */
for(i = 0; i < 2; i++){
printf("Your name is %s and your age is %d \n", student->p[i]->name, student->p[i]->age);
}
return 0;
}
I hope you can figured out what's going on.
Here is a part of a debugging session.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: C:\Users\NTWALI\Desktop\tests\help\bin\Debug/help.exe
[New thread 11408.0x1228]
Error: dll starting at 0x770a0000 not found.
Error: dll starting at 0x76ab0000 not found.
Error: dll starting at 0x770a0000 not found.
Error: dll starting at 0x76d40000 not found.
Program received signal SIGSEGV, Segmentation fault.
0x0040146f in insert (sample=0x6816c0, _name=0x409031 "ntwali", _age=22) at C:\Users\NTWALI\Desktop\tests\help\main.c:44
44 sample->p[sample->id]->name = _name;
(gdb) p sample
$4 = (struct person *) 0x6816c0
(gdb) p sample->p
$5 = (struct element **) 0x681750
(gdb) p sample->p[0]
$6 = (struct element *) 0xbaadf00d
(gdb) p sample->p[1]
$7 = (struct element *) 0xbaadf00d
(gdb)
As you see in the code comment's, the data the program gives when it works, don't match with what one gets with GDB.
Thanks for helping.
You haven't allocated any memory for an element as far as I can see.
Here you allocate memory for a pointer to an element:
sample->p = (struct element** ) malloc(_size*sizeof(struct element*));
If the presence of a debugger alters the way your program behaves, you are very likely misusing memory or threads. Just like daven11 points out, you are not allocating the elements itself.
The root cause of your problem is that you are allocating pointers to struct element, but those pointers are uninitialised - you're not allocating any actual struct element objects. When you dereference those invalid pointers, you get undefined behaviour.
There is also no need to allocate _size of the struct person structs - you only ever use one. Your struct person should look like (note type of p is different):
struct person{
struct element *p;
size_t size;
unsigned int id;
};
and your init() function should then look like:
struct person* init(int _size)
{
if(_size < 1)
{
printf("You gonna have to make some choices \n");
exit(1);
}
struct person* sample = malloc(sizeof *sample);
sample->p = malloc(_size * sizeof sample->p[0]);
sample->id = 0;
sample->size = _size;
return sample;
}
The insert() function should look like:
void insert(struct person* sample, char* _name, int _age)
{
if (sample->id >= sample->size) {
sample->size *= 2;
sample->p = realloc(sample->p, sample->size * sizeof sample->p[0]);
if(sample->p == NULL){
printf("Get a new RAM buddy \n");
exit(1);
}
}
sample->p[sample->id].name = _name;
sample->p[sample->id].age = _age; /* of course, this will cause trouble too because it has the same construct as the previous one */
sample->id++;
}
The main function should then use student->p[i].name and student->p[i].age to access the data.
here you are using p[] without first initializing it to point to anything. you have only allocated space for the pointers but haven't initialized them to point to anything. So when you do
sample->p[sample->id]->name = _name;
sample->p[sample->id]->age = _age;
p is pointing somewhere in memory and you are modifying what it points to.
instead, insert a
sample->p[sample->id] = malloc(struct element);
sample->p[sample->id]->name = _name;
sample->p[sample->id]->age = _age;
and it should work
PS. normally you don't cast malloc in C

Why I've allocated a pointer memory in a function, but it's also NULL?

The code confused me.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void create_int(int *p)
{
p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
You are not passing the pointer value back from the function. Try:
void create_int(int **p) {
*p = (int *) malloc(sizeof(int));
}
int main() {
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
The variable p in the function create_int is a copy of the variable p in main. So any changes made to p in the called function does not get reflected in main.
To make the change get reflected in main you need to either:
Return the changed value:
int* create_int(int *p) {
p = malloc(sizeof(int));
// err checking
return p:
}
...
// in main:
p = create_int(p);
Or pass the address of p as:
void create_int(int **p) {
*p = malloc(sizeof(int));
// err checking
}
...
// in main:
create_int(&p);
You need a pointer to a pointer like this:
void create_int(int **p)
{
*p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
As folks have pointed out, it's failing since you're not actually changing the pointer that the caller has.
A different way to think about the code might be to notice that it's basically wrapping malloc(), i.e. it's doing a memory allocation but with intelligence added. In that case, why not make it have the same prototype (=call signature) as malloc()? That makes it clearer in the caller's context what's going on, and easier to use:
int * create_int(void)
{
return malloc(sizeof (int));
}
int main(void)
{
int *p = create_int();
assert(p != NULL);
return 0;
}
Also, in C you should never cast the return value of malloc() (see Do I cast the result of malloc?).
You need to send a pointer to a pointer to be able to assign a memory to it via a function
void create_int(int **p)
{
*p = (int*)malloc(sizeof_int));
}
int main()
{
int* p = NULL;
create_int(&p);
assert(p != NULL);
return 0;
}
Your code contains two pointers: one in the create_int function and another one in main. When you call create_int, a copy of the pointer in main is made and used, then eliminated when the create_int function returns.
So, any changes you did to the copy within create_int remain there and are not propagated back to main.
The only way to propagate changes between functions in C (aside from, obviously, returning new values) is to pass a pointer to the changed values. This way, while the pointer being passed will be copied, the value that it points to will be the same, so changes will apply.
Since you're trying to change a pointer, you need a pointer-to-pointer.
void create_int(int **pp)
{
// this changes the pointer that `p` points to.
*pp = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
// this sends a pointer to the pointer p in main
create_int(&p);
assert(p != NULL);
return 0;
}

Resources