Reputation: 183
Suppose I have a struct like this..
struct object{
int id;
char *name;
node *list_head; //a pointer to the head of a linked list
};
typedef struct object object;
I statically declared a struct variable. I have to pass this by value to a function which inserts an element to a list in the temp_obj
as shown below.
We can assume that the add_element
and print_list
function are working fine.
If I print the list after function_a
then it won't print the inserted element.
I think this is because I am passing the structure as a value so the change made in function_a
won't reflect to the structure declared before the function_a
.
But I have to pass the structure by value because of given interface. In this case, what can I do to reflect the change to the original structure?
object temp_obj
function_a(temp_obj);
print_list(temp_obj.list_head);
void function_a(object obj){
//add an element to the list
int num = 1;
add_element(&obj.list_head, num);
}
Upvotes: 1
Views: 3837
Reputation: 753735
You can do it subject to a not too onerous condition, but it is a cheat of sorts.
If the add_element()
function adds the new element at the end of the list, not at the head, and if you arrange things so that there is an initial node in the list, then you can, just about, do it.
Proof:
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void err_exit(const char *fmt, ...);
typedef struct node node;
typedef struct object object;
struct object
{
int id;
char *name;
node *list_head; //a pointer to the head of a linked list
};
struct node
{
node *next;
object *data;
};
static void add_element(node **list, int value)
{
assert(list != 0);
object *new_objt = calloc(sizeof(object), 1);
node *new_node = calloc(sizeof(node), 1);
if (new_objt == 0 || new_node == 0)
err_exit("Out of memory in %s\n", __func__);
node *next = *list;
while (next->next != 0)
next = next->next;
next->next = new_node;
new_node->data = new_objt;
new_objt->id = value;
}
static void print_list(const node *list)
{
assert(list != 0);
node *next = list->next;
printf("List: ");
while (next != 0)
{
if (next->data != 0)
printf("%d ", next->data->id);
next = next->next;
}
printf("EOL\n");
}
static void function_a(object obj)
{
int num = 1;
add_element(&obj.list_head, num);
}
int main(void)
{
node temp_node = { 0, 0 };
object temp_obj = { 0, 0, &temp_node }; // Key trick!
print_list(&temp_node);
function_a(temp_obj);
print_list(&temp_node);
function_a(temp_obj);
print_list(&temp_node);
return 0;
}
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errno != 0)
fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
putc('\n', stderr);
exit(EXIT_FAILURE);
}
Compilation
gcc -O3 -g -std=c99 -Wall -Wextra node.c -o node
Output:
List: EOL
List: 1 EOL
List: 1 1 EOL
If the object of the exercise is to defeat a brain-dead interface, this works around it. If the object of the exercise is to create a usable interface, then you probably don't do it this way; you pass a pointer to a structure into function_a()
so you can change the list_head
.
Upvotes: 2
Reputation: 51840
list_head
is a pointer, so why do you do this:
add_element(&obj.list_head, num);
This is the correct way:
add_element(obj.list_head, num);
The head of a list is the first element in it. That never changes, which is why you don't need to pass &obj.list_head
. You only need the address of the list head, not the address of the pointer that holds the address of the list head.
Your add_element() implementation should look something like this, assuming your 'node' struct has a 'next' member:
void add_element(node* head, int num)
{
/* Iterate over the list that starts at 'head' and when we reach the end,
insert 'num' as a new element */
node* cur = head;
while (cur->next != NULL)
cur = cur->next;
/* We're at the end. */
cur->next = malloc(sizeof(node));
cur->next->next = NULL;
cur->next->num = num;
}
Passing by value will work correctly, since your object
struct has pointer members. That means copies of object
variables will still point to the same data since they're all shallow copies (the same data is shared by all copies.)
Upvotes: 0
Reputation: 27210
You can not do it with pass by value..you must change your interface design and use pass by refference
Upvotes: 0
Reputation: 29265
You're screwed!
If you can't change the interface, then there is no way to make "pass by value" act like "pass by reference".
Your options are change the interface to take an object *
or make the function return an object
(or object*
) - all of these options require a change to the interface.
Upvotes: 2