假设我有这样的结构..
struct object{
int id;
char *name;
node *list_head; //a pointer to the head of a linked list
};
typedef struct object object;
我静态地声明了一个struct变量。我必须通过值将它传递给一个函数,该函数将元素插入temp_obj
中的列表,如下所示。
我们可以假设add_element
和print_list
函数正常工作。
如果我在function_a
之后打印列表,那么它将不会打印插入的元素。
我认为这是因为我将结构作为值传递,因此function_a
中所做的更改不会反映在function_a
之前声明的结构。
但是由于给定的接口,我必须按值传递结构。 在这种情况下,我该怎么做才能反映原始结构的变化?
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);
}
答案 0 :(得分:2)
你搞砸了!
如果你不能改变界面,那么就没有办法让“按值传递”的行为就像“按参考传递”一样。
您的选项是更改接口以获取object *
或使该函数返回object
(或object*
) - 所有这些选项都需要更改接口。
答案 1 :(得分:2)
你可以根据一个不太繁重的条件来做这件事,但这是一种欺骗。
如果add_element()
函数在列表的末尾添加新元素,而不是在头部,并且如果你安排事情以便列表中有一个初始节点,那么你可以,做到这一点。
证明:
#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);
}
汇编
gcc -O3 -g -std=c99 -Wall -Wextra node.c -o node
输出:
List: EOL
List: 1 EOL
List: 1 1 EOL
如果练习的目的是打败脑死亡的界面,这就可以解决它。如果练习的目的是创建一个可用的界面,那么你可能不会这样做;您将指向结构的指针传递到function_a()
,以便更改list_head
。
答案 2 :(得分:0)
您无法通过按值传递来实现..您必须更改界面设计并使用通过参考传递
答案 3 :(得分:0)
list_head
是一个指针,为什么要这样做:
add_element(&obj.list_head, num);
这是正确的方法:
add_element(obj.list_head, num);
列表的头部是其中的第一个元素。这永远不会改变,这就是你不需要传递&obj.list_head
的原因。您只需要列表头的地址,而不是包含列表头地址的指针的地址。
你的add_element()实现看起来应该是这样的,假设你的'node'结构有一个'next'成员:
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;
}
按值传递将正常工作,因为您的object
结构具有指针成员。这意味着object
变量的副本仍将指向相同的数据,因为它们都是浅层副本(所有副本共享相同的数据。)