1

此函数不返回预期结果(交换ab)。

#include<stdio.h>
#include<stdlib.h>

void swap_one(int *x, int *y) {
    int *tmp;
    tmp = x;
    x = y;
    y = tmp;
    printf("x = %d y = %d\n", *x, *y);
}

void swap_two(int *x, int *y) {

}

int main() {
    int a = 5;
    int b = 100;
    printf("Before a = %d b = %d\n\n", a, b);
    int *p = (int *) malloc(sizeof(int));
    int *q = (int *) malloc(sizeof(int));
    p = &a;
    q = &b;

    swap_one(p, q);
    printf("After a = %d b = %d\n", a, b);
    return 0;
}

但是下面的代码按预期工作。

#include <stdlib.h>
#include <stdio.h>
typedef struct ListElmt_ {
    void *data;
    struct ListElmt_ *next;
} ListElmt;

typedef struct List_ {
    int size;
    int (*match) (const void *key1, const void *key2);
    void (*destroy) (void *data);
    ListElmt *head;
    ListElmt *tail;
} List;

void list_init (List *list) {
    list->size = 0;
    list->match = NULL;
    list->destroy = NULL;
    list->head = NULL;
    list->tail = NULL;
}

int list_ins_next(List *list, ListElmt *element, void *data) {
    ListElmt *new_element;
    /* Alocate storage for the element. */
    if ((new_element = (ListElmt *) malloc(sizeof(ListElmt))) == NULL) return -1;
    /* new_element->data is of type void *. So we use (void *) data */
    new_element->data = (void *)data;
    if (element == NULL) {
        /* Handle insertion at the head of the list */
        if (list->size == 0) list->tail = new_element;
        new_element->next = list->head;
        list->head = new_element;
    } else {
        if (element->next == NULL) list->tail = new_element;
        new_element->next = element->next;
        element->next = new_element;
    }
    list->size++;
    return 0;
}

/* Print the list */
static void print_list(const List *list) {
    ListElmt *element;
    int *data;
    int i;
    /* Display the linked list */
    fprintf(stdout, "List size is %d\n", list->size);
    i = 0;
    element = list->head;
    while (1) {
        data = element->data;
        fprintf(stdout, "list[%03d] = %03d\n", i, *data);
        i++;
        if (element->next == NULL) {
            break;
        } else {
            element  = element->next;
        }
    }
}

int main(int argc, char **argv) {
    List list;
    ListElmt *element;
    int *data;
    int i;
    /* list = (List *) malloc(sizeof(List)); */
    /* Initialize the linked list */
    List *listPtr;
    listPtr = &list;
    list_init(listPtr);
    /* Perform some linked list operations */
    element = listPtr->head;
    for (i = 10; i > 0; i--) {
        if ( (data = (int *) malloc(sizeof(int))) == NULL) return 1;
        *data = i;
        if (list_ins_next(listPtr, NULL, data) != 0) return 1;
    }
    print_list(listPtr);
    fprintf(stdout, "Value in *data is:%d\n", *data);
    return 0;
}

问题是:在swap_one函数中,x=y类似于new_element->next = element->nextor element->next = new_element。为什么new_element->next = element->nextandelement->next = new_element工作但x =y在 swap_one 函数中不交换aand b

很抱歉有很多代码,但我真的对这个感到困惑。

谢谢。

4

3 回答 3

2

指针传递。交换这些变量中保存的指针值不会实现它们指向的数据的交换。

  1. 想象一下,&p地址是 0x1000,&q地址是 0x1004。

  2. 现在,您调用swap_one(&p, &q);-- 指针x的值为 0x1000,指针的y值为 0x1004。

  3. 您现在交换指针值。 x现在是 0x1004 指向,q现在y是 0x1000 指向p. 然而,pq没有在记忆中移动。您只更改了存储在指针中的值。

  4. 当函数返回时,这些指针超出范围。 p并且q仍然保持与以前相同的内容,因为您从未修改过它们。

因此,要交换它们指向的值,您必须取消引用指针以获取实际数据。

int tmp = *x;
*x = *y;
*y = tmp;

将此与您的链接列表示例进行对比。在该示例中,您有一个指向结构的指针,并且您正在修改其next成员。这实际上修改了内存中的指针,因为这是您的链表所在的位置以及它如何存储值。

但是,如果您将这些指针指向某个假设函数,则会出现同样的问题:swap_next(node **x, node **y);--x并且y只是指向指针值的局部变量。如果您交换它们,它们不会修改除自身之外的任何内容。所以同样的修复适用:要更改指向的数据,您必须遵循指针。

于 2021-12-16T05:11:54.583 回答
2

您的swap_one函数只是交换传递给函数的指针,而不是指针指向的内容。因此,您所做的任何更改都不会反映在函数之外。

您需要取消引用这些指针以读取/写入它们指向的内容。

void swap_one(int *x, int *y) {
    int tmp;
    tmp = *x;
    *x = *y;
    *y = tmp;
    printf("x = %d y = %d\n", *x, *y);
}

list_ins_next函数中,您正在更改指针指向的内容,因此可以在函数外部看到更改。

于 2021-12-16T05:12:02.017 回答
0

变量xy是 的局部变量swap_one()swap_one()这是调用函数时发生的情况:

p = &a;
q = &b;

p (pointer)        q (pointer)
---                ---
| |---+            | |---+
---   |            ---   |
      |                  |
   a ----             b ----
     |  |               |  |
     ----               ----

swap_one(p, q)从函数调用main()函数:

p (pointer)        q (pointer)
---                ---
| |---+            | |---+
---   |            ---   |
      |                  |
   a ----             b ----
     |  |               |  |
     ----               ----
      |                  |
      |                  |
---   |            ---   |
| |---+            | |---+
---                ---   
x (pointer)        y (pointer)
pointing to a      pointing to b

(x and y are parameters of swap_one()) 

执行这些swap_one()函数语句后:

tmp = x;
x = y;
y = tmp;

指针x将指向该指针y指向的地址,并且指针y将指向该指针xswap_one()被调用时指向的地址。

 p (pointer)        q (pointer)
---                ---
| |---+            | |---+
---   |            ---   |
      |                  |
   a ----             b ----
     |  | -----+        |  |
     ----      |        ----
               |         | 
      +--------|---------+
---   |        |   ---   
| |---+        +---| |
---                ---   
x (pointer)        y (pointer)
pointing to b      pointing to a 

请注意,指针p和指针q仍然分别指向变量ab。这就是为什么当swap_one()函数返回时,变量的值ab没有被交换。

如果您想交换变量的值,其地址作为参数传递给swap_one()函数而不是取消引用指针参数并替换该位置的值,即您应该在swap_one()函数中执行以下操作:

    tmp = *x;
    *x = *y; 
    *y = tmp;

通过这些更改,其地址传递给函数的变量的值swap_one()将被交换,因为现在,您正在取消引用指针x(ie *x) 和指针y(ie *y) 并在该位置分配值。

现在,进入第二个代码的这一部分。element不考虑的情况NULL

    } else {
    if (element->next == NULL) list->tail = new_element;
    new_element->next = element->next;
    element->next = new_element;

请注意,element指针是类型的ListElmt,是的,它也是list_ins_next()函数的局部指针变量。但是,这里我们使用这个局部指针变量来修改它所指向的结构成员的值。

    new_element (pointer of type ListElmt)
      ----
      |  |-----+
      ----     |
               |
           -----------
           |    |    |
           -----------
             ^      ^
             |      |
          data     next
          pointer  pointer


    element (pointer of type ListElmt, which is pointing to an existing node of list
      ----   passed to list_ins_next() function)
      |  |-----+
      ----     |
               |
           -----------
           |    |    |
           -----------
             ^      ^
             |      |
          data     next
          pointer  pointer

请注意,这

new_element->next 

(*new_element).next

这意味着,取消引用new_element指针(转到它指向的位置)并访问该next位置的指针。

所以这

new_element->next = element->next;

将使new_element->next指针指向element->next指针所指向的内容和 this

element->next = new_element; // same as (*element).next = new_element;

将使element->next指针指向new_element指针所指向的内容。执行这些语句后,

        new_element (pointer of type ListElmt)
      ----
      |  |-----+
      ----     |
               |
           -----------
      +--- |    |    |-------> (pointing to what element->next was pointing at)
      |    -----------
      |      ^      ^
      |      |      |
      |   data     next
      |   pointer  pointer
      --------------------+
                          |
    element               |
      |  |-----+          |
      ----     |          |
               |          |
           -----------    |
           |    |    |----+
           -----------
             ^      ^
             |      |
          data     next
          pointer  pointer

因此,如果要更改传递给函数的指针,则必须在调用函数中取消引用它。


如果您仍然感到困惑,那么只需检查以下内容:

在您的第二个代码中,如果您执行的操作与您在第一个代码中所做的相同:

example = <some pointer of type ListElmt>;

即分配一些其他相同类型的指针example,这将发生:

     element 
      ----                 -----------
      |  |---------------> |    |    |
      ----                 -----------

         (The original ListElmt type element
          whose address passed to list_ins_next() function)
           -----------
           |    |    |
           -----------
             ^      ^
             |      |
          data     next
          pointer  pointer

现在,当list_ins_next()函数返回时,其地址传递给该函数的原始元素将保持不变。


额外的:

在这里,您的程序正在泄漏内存:

    int *p = (int *) malloc(sizeof(int));
    int *q = (int *) malloc(sizeof(int));
    p = &a;
    q = &b;

因为分配的内存引用,指针pq,(使用malloc())将在您分别分配和&a&b丢失。pq

于 2021-12-16T06:15:40.913 回答