1

假设我有一个这样的结构..

struct object{
     int id;
     char *name;
     node *list_head; //a pointer to the head of a linked list
};

typedef struct object object;

我静态声明了一个结构变量。我必须将其按值传递给一个函数,该函数将一个元素插入到temp_obj如下所示的列表中。

我们可以假设add_elementandprint_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);
}
4

4 回答 4

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.

于 2012-11-22T05:26:27.670 回答
2

你完蛋了!

如果你不能改变接口,那么就没有办法让“按值传递”像“按引用传递”一样。

您的选项是更改接口以采用一个object *或使函数返回一个object(或object*) - 所有这些选项都需要更改接口。

于 2012-11-22T04:52:30.433 回答
0

不能通过值传递来做到这一点..您必须更改界面设计并使用引用传递

于 2012-11-22T04:54:24.447 回答
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变量的副本仍将指向相同的数据,因为它们都是浅副本(所有副本共享相同的数据。)

于 2012-11-22T05:01:36.580 回答