returning a pointer as a function parameter - c

I have a struct, for example:
typedef struct{
int num;
} S, *Sp;
now, what I want to do is create a pointer of this type (without allocating memory), pass is to a function as a parameter and inside the function allocate the memory etc.
something like
void foo(Sp p){
p = malloc.....
p->num = ....
}
and then in main do something like this:
Sp new = NULL;
foo(new);
but after foo is done 'new' remains NULL, like it was never allocated. I feel like I'm doing something wrong here.
(this is a small part of a HW assignment, and I can't change the function definition.)

You should understand that in C, arguments are passed by value (not by reference). So when a function changes a formal argument, no change happens in the caller function. Hence, pass the address of your pointer.
void foo(S**pp) {
*pp = malloc(sizeof(S));
if (!*pp) { perror("malloc"); exit(EXIT_FAILURE); };
// fill *pp
}
and call
S* ptr;
foo (&ptr);
Actually, it is much more common to have the building function return a pointer:
S* make_s(void) {
S* p = malloc(sizeof(S));
if (!p) { perror("malloc"); exit(EXIT_FAILURE); };
// fill p
return p;
}
Then call
S* ptr = make_s ();
The important thing is to document a convention about who should free the pointer. If the allocated structure contains internal pointer, make a routine delete_s which frees the internal pointer and the whole pointed structure.
BTW, avoid using typedef for pointers (like your Sp), you really want to know what is a pointer at a glance. Don't use new or delete in public C function names, because you may want later your header files to be included by C++ code.

void foo(Sp *p){
*p = malloc.....
*p->num = ....
}
then
Sp new = NULL;
foo(&new);
if you want to keep the prototype of the function as void foo(Sp p), you have to go:
Sp new = (Sp) malloc(sizeof(S));
foo(new);

If you can't change the function declaration, then you need to allocate the memory for the structure in main.
void foo(Sp ptr){
ptr->num = ....
}
In main:
Sp itemPtr = malloc...;
foo( itemPtr );
Or this in main:
S item;
foo( &item );

Related

Setting a Pointer to `NULL` Inside a Function and Having it Stay `NULL` in C

I'm fairly new to the C programming language, and I am trying to make an idiomatic pattern for creating structures (i.e. a series of standard constructors, destructors, etc.) like so:
typedef struct _OBJECT
{
char *data;
} object_t;
object_t *object_new(char *data)
{
object_t *ret = malloc(sizeof(*ret));
if (ret != NULL)
ret->data = data;
return ret;
}
void object_delete(object_t *obj)
{
if (obj != NULL)
{
free(obj);
obj = NULL;
}
}
I seem to be having an issue with making a destructor-esque function, though, as I am unable to set the argument of the function to NULL after freeing it. I am fairly sure this has to do with the fact that data declared on the stack in a callable object is impersistent. Is there a way to make this declaration persistent or is setting the pointer to NULL outside the function the best way of handling things?
I am unable to set the argument of the function to NULL after freeing it...
If you want to set the argument to NULL, change the parameter type of function to double pointer and pass the address of object to the function. Dereferencing the function parameter will give you the object, whose address passed as argument, which then you can set to NULL after deallocating memory. That said, below are the changes you need to do in object_delete() function:
void object_delete(object_t **obj) // change parameter type to double pointer
{
if (*obj != NULL) // dereferencing parameter will give object
{
free(*obj); // free object
*obj = NULL; // set object to NULL
}
}
Call object_delete() function like this:
int main() {
object_t * x = object_new ("str");
object_delete (&x); // pass address of pointer x
// check x
printf ("x is %sNULL\n", x == NULL ? "" : "not ");
return 0;
}
If you want to modify the pointer's value, then you need to pass a pointer to the pointer:
void object_delete(object_t **obj)
{
free(*obj);
*obj = NULL;
}
int main() {
char data[] = "foo";
object_t *obj = object_new(data);
object_delete(&obj);
}
Note that there's not much point in null-testing the pointer, because free does that anyway.
Pointers are values, and C is a pass-by-value language.
In other words, object_t *obj is a local copy of the pointer passed to object_delete.
One option is another level of indirection.
void object_delete(object_t **obj)
{
free(*obj);
*obj = NULL;
}
int main(void) {
object_t *foo = object_new("42");
object_delete(&foo);
}

why can i free a part of a struct it free all the struct

Hi I need to write a function free to the key element of a map and free to the data element of the map.
I defined two struct obviously with their typedef:
struct player_stats
{
int player_id;
Player_data data_of_player;
Player_stats next;
};
struct player_data
{
int number_of_wins;
int number_of_losses;
int number_of_equals;
};
the problem is the creation of the function freePlayerKey:
I need to write a function that do free to the int player_id.
i tried this ,it 's working but oddly it also do free to the player_data
void freePlayerId (void* player_id_to_free)
{
free(player_id_to_free);
}
for example I wrote a little test:
doron->player_id=10;
doron->data_of_player->number_of_wins=20
freePlayerId(&(doron->player_id));
printf("%d\n",doron->player_id);
printf("%d\n",doron->data_of_player->number_of_wins);
i expect that it will be
number not defined
20
but it does:
number not defined
number not defined
complete code here
void* copyPlayerId (void* player_id_to_copy)
{
if(player_id_to_copy==NULL)
{
return NULL;
}
int* id_copied = malloc(sizeof(*id_copied));
if(id_copied==NULL)
{
return NULL;
}
*id_copied=*(int*)player_id_to_copy;
return (void*) id_copied;
}
void* copyDataPlayer (void* player_data_to_copy)
{
if(player_data_to_copy==NULL)
{
return NULL;
}
Player_data new_copy=malloc(sizeof(*new_copy));
if(new_copy==NULL)
{
return NULL;
}
new_copy->number_of_wins=(*(Player_data *)player_data_to_copy)->number_of_wins;
new_copy->number_of_equals=(*(Player_data *)player_data_to_copy)->number_of_equals;
new_copy->number_of_losses=(*(Player_data *)player_data_to_copy)->number_of_losses;
return (void*) new_copy;
}
void freePlayerId (void* player_id_to_free)
{
free(player_id_to_free);
}
void freeDataPlayer(void* player_data_to_free)
{
Player_data to_free=*(Player_data*) player_data_to_free;
free(&(to_free->number_of_wins));
free(&(to_free->number_of_equals));
free(&(to_free->number_of_losses));
free(player_data_to_free);
}
struct player_stats
{
int player_id;
Player_data data_of_player;
Player_stats next;
};
struct player_data
{
int number_of_wins;
int number_of_losses;
int number_of_equals;
};
int main()
{
Map player=createPlayerMap();
Player_stats doron=malloc(sizeof (*doron));
if(doron==NULL)
{
return 1;
}
Player_data new_data=malloc(sizeof (*new_data));
new_data->number_of_equals=3;
new_data->number_of_losses=0;
new_data->number_of_wins=20;
doron->player_id=346267420;
doron->next=NULL;
doron->data_of_player=new_data;
//insert doron in the map
mapPut(player,&doron->player_id,&doron->data_of_player);
//create a copy
Player_stats doron_copy=malloc(sizeof (*doron_copy));
doron_copy->player_id=*((int*)copyPlayerId(&(doron->player_id)));
doron_copy->data_of_player=(Player_data)copyDataPlayer(&(doron->data_of_player));
doron_copy->data_of_player->number_of_equals=1000;
doron_copy->data_of_player->number_of_losses=2000;
doron_copy->data_of_player->number_of_wins=500000;
doron_copy->player_id=8;
doron_copy->next=NULL;
printf("%d\n",doron->player_id);
printf("%d\n",doron_copy->player_id);
printf("%d\n",doron->data_of_player->number_of_wins);
printf("%d\n",doron_copy->data_of_player->number_of_wins);
//doing free to key element(player id of doron
freePlayerId(&doron->player_id);
printf("%d\n",doron->player_id);
printf("%d\n",doron_copy->player_id);
printf("%d\n",doron->data_of_player->number_of_wins);
printf("%d\n",doron_copy->data_of_player->number_of_wins);
return 0;
}
You can only free the memory allocated by the malloc family functions
You cant free "part of the struct" only the whole allocated block.
You cant dereference the freed block.
You cant pass to free any other reference than returned by malloc family functions.
There are several problems with this code.
First, you can only pass to free a pointer that was returned from malloc, realloc, or calloc. You're instead passing in the address of a struct member which would not have been allocated. Doing so triggers undefined behavior.
Assuming doron is what was allocated, if you were to free that, it's also not allowed to dereference a pointer to memory that has been freed. That is also undefined behavior.
Regarding your edit, there's a lot that needs to be fixed.
On this line:
doron_copy->player_id=*((int*)copyPlayerId(&(doron->player_id)));
You return allocated space containing a copy of doron->player_id and dereference that pointer to assign the result to doron_copy->player_id. You loose the pointer that the function returned so this is a memory leak. This can be replaced with:
doron_copy->player_id = doron->player_id;
And copyPlayerId can be removed entirely, as can freePlayerId.
Then you have this:
void* copyDataPlayer (void* player_data_to_copy)
This function is working with void * as the parameter and the return types. There's no need to use void * here because you know the type of what's being passed and what's being returned. This should be changed to:
Player_data copyDataPlayer(Player_data player_data_to_copy)
And you can remove the casts in the function:
new_copy->number_of_wins=player_data_to_copy->number_of_wins;
new_copy->number_of_equals=player_data_to_copy->number_of_equals;
new_copy->number_of_losses=player_data_to_copy->number_of_losses;
And change the call to:
doron_copy->data_of_player=copyDataPlayer(doron->data_of_player);
This brings up another point. Although you don't show the definition of Player_data and Player_stats, it's apparent that these are pointer types. It's bad style to hide pointers behind a typedef as it can mask the fact that you're using a pointer and cause confusion.
Then there's freeDataPlayer:
void freeDataPlayer(void* player_data_to_free)
{
Player_data to_free=*(Player_data*) player_data_to_free;
free(&(to_free->number_of_wins));
free(&(to_free->number_of_equals));
free(&(to_free->number_of_losses));
free(player_data_to_free);
}
As with copyDataPlayer the parameter should have the type of what you're actually passing in. As mentioned before, you also don't need to call free on the element addresses because they were not returned from malloc. So this function should be:
void freeDataPlayer(Player_data player_data_to_free)
{
free(player_data_to_free);
}

deallocating various pointers in a function that repeats several times

I have a void function that sends a struct value
my func' is repeated several times. the struct members were dinamically allocated. So how can I free them?
I guess that if I free them in the func' itself, it will destroy the struct object that has been sent.
void func(){
typedef struct ENTRY {
int entry_num;
char* English_term;
char** translations;
enum types type;
}ENTRY;
ENTRY new_entry = { .entry_num = 0,
.English_term = temp,
.translations = (char**)malloc(tr_amnt * sizeof(char*)),
.type = 0
}
...
...
another_function(new_entry);
// free all pointers?
}
Yes, as you're not returning the pointers from the function in any way (neither via return statement nor via function parameters), you can free() the allocated memory pointed to by those pointers.
It's expected that the another_function() will have it's own copy of the arguments passed, if needed to retain the value beyond the function call.

pointer to a structure within a structure in C

I have a structure (let's call it structure1) which holds a pointer to another structure (structure2), this way.
typedef struct structure{
structure2 *pointer
}structure;
structure structVariable;
structVariable.pointer = functionThatReturnsAPointerToStructure2Variable();
The thing is, as the program changes context (for example, when calling functions), the return value of the following code changes
structVariable.pointer->someAttribute
Any idea of why this might be happening? If you need more info please ask. Thanks!
MORE INFO
This is the real-deal
structure would be this
typedef struct CPU{
int variableCounter;
int instructionPointer;
char *currentInstruction;
t_list *dataDictionary_list;
u_int32_t currentContext;
PCB *assignedPCB;
CPU_STATUS status;
}CPU;
And this is how I assign the pointer (PCB *pointer)
PCB *pcb_createFromScript(const char *script){
t_medatada_program *metadata = metadatada_desde_literal(script);
PCB *pcb = malloc(sizeof(PCB));
pcb->instructionCount = metadata->instrucciones_size;
pcb->tagCount = metadata->cantidad_de_etiquetas;
pcb->functionCount = metadata->cantidad_de_funciones;
int codeSegmentSize = strlen(script);
int tagIndexSize = 0;
if(metadata->etiquetas != 0){
tagIndexSize = strlen(metadata->etiquetas);
}
int instructionIndexSize = metadata->instrucciones_size * sizeof(t_intructions);
pcb_getSegments(pcb,1024,codeSegmentSize,tagIndexSize,instructionIndexSize);
pcb->currentContext = pcb->stackSegment;
pcb->variableCounter = 0;
memory_write(pcb->codeSegment,0,codeSegmentSize,script);
memory_write(pcb->tagIndexSegment,0,tagIndexSize,metadata->etiquetas);
memory_write(pcb->instructionIndexSegment,0,instructionIndexSize,(void *)metadata->instrucciones_serializado);
pcb->uniqueId = (int) random();
return pcb;
}
And then I assign it this way (myCPU is global), that's why I call it inside cpu_getPCB without passing it as a parameter
cpu_getPCB(*dummyPCB);
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
Here is some speculation.
If you are modifying the object that structVariable.pointer points to in some function, then when you try to read structVariable.pointer->someAttribute, that value will change to reflect to modification to the object.
Another possibility, as the other answer mentioned, is that structVariable.pointer is pointing to local memory (stack memory for a function) which can easily be overwritten on a new function call. That can be corrected by using malloc to do heap allocation instead of stack allocation.
Here is the first and most obvious issue. You are taking the address of a parameter and assigning it to myCPU.assignedPCB.
Since C is pass-by-value, you have copied it instead of capturing the original. Moreover, the parameter has the same lifetime as a local variable, and will go away when the function returns.
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
You can fix it by passing a pointer instead, since you are in C and do not have access to the reference type.
void cpu_getPCB(PCB* myPCB){
myCPU.currentContext = myPCB->currentContext;
myCPU.assignedPCB = myPCB;
}
The "structure2 *pointer" will be pointing at a piece of memory that will disappear when you change context. Allocate the Structure2 variable and free it when it's no longer needed

Question about passing a variable created in a function

Suppose there exists a function which returns a message
say of the following format:
struct message
{
void* data;
}msgG;
Which would be the best way to extract the data (i.e. Get the message accessible to fun1 in the code):
1- using a global variable
2- Using double pointers(pointer to a pointer)
//Note: msgG is the global variable
void fun2(struct message **ptr)
{
**ptr = msgCreate(); // msgCreate returns a type struct message;
msgG = msgCreate();
}
void fun1()
{
....
.....
struct message *ptr;
ptr = malloc(sizeof(struct message));
fun2(&ptr);
...
}
Now we have the message stored in msgG and ptr ?
Which is the better one? Using global variable or accessing the pointer since one is allocated in the heap and the other in the bss(not sure of this)??
Is there any other way to deal with this kind of situation?
Don't use a global variable. What you're trying to do can be done this way:
void fun2(struct message *ptr)
{
*ptr = msgCreate();
}
void fun1()
{
struct message *m = malloc(sizeof *m);
if (m == NULL) {
/* error handling */
}
fun2(m);
}
If struct message is big, consider not having a function returning such a struct. In most of the cases, it is more efficient to return a pointer to some memory than to return a big automatic variable from a function.
It's good practise to avoid globals.
Note: if you are trying to code object-oriented in C, have a look to this documentation ooc.pdf
It can be as simple as this:
struct message
{
void* data;
} msgG;
void fun2(struct message the_msg)
{
/* access the_msg.data */
}
void fun1()
{
struct message *ptr;
ptr = malloc(sizeof(struct message));
ptr->data = ... /* initialize it to something */
fun2(*ptr);
}
But this way, fun2 won't be able to manipulate the_msg, because it's passed a copy of the structure by-value. It will be able to manipulate the stuff pointed to by the data pointer inside the_msg, because that's a pointer.
If you want to manipulate the contents of the_msg itself, such as retarget the data pointer, fun2 should accept a pointer to message (a double pointer is unnecessary for this).
And a global variable is almost always a bad solution. Don't use it.

Resources