交换两个结构的元素

Swap elements of two structures

提问人:noobee 提问时间:1/6/2022 更新时间:1/6/2022 访问量:351

问:

我已经将我的问题简化为这个小 C 程序。请注意,我正在自学 C。我在指针方面遇到了真正的麻烦!

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

typedef struct Elmt_ {
    int *i;
    struct Elmt_ *next;
} E;

void swap_1(E *x, E *y) {
    int *temp = NULL;
    temp = x->i;
    x->i = y->i;
    y->i = temp;
}

void swap_2(E *x, E *y) {
    int *temp=NULL;
    temp = malloc(sizeof(int));
    *temp = *(x->i);
    *(x->i) = *(y->i);
    *(y->i) = *temp;
}

int main() {
    E *p, *q, *r, *s;

    int a, b;
    a = 8;
    b = 50;

    p = malloc(sizeof(E));
    q = malloc(sizeof(E));
    p->i = &a;
    p->next = NULL;

    q->i = &b;
    q->next = NULL;
    printf("Initially, *(p->i)=%d *(q->i)=%d\n", *(p->i), *(q->i));
    swap_1(p,q);
    printf("After swap_1, *(p->i)=%d *(q->i)=%d\n", *(p->i), *(q->i));

    r = malloc(sizeof(E));
    s = malloc(sizeof(E));
    r->i = &a;
    s->i = &b;
    printf("Initially, *(r->i)=%d *(s->i)=%d\n", *(r->i), *(s->i));
    swap_2(r,s);
    printf("After swap_2, *(r->i)=%d *(s->i)=%d\n", *(r->i), *(s->i));
    return 0;
}

问:在上面的程序中,交换所指向的整数值的正确方法是否正确?swap_1swap_2i

我看到这两个函数似乎都正确地交换了作为参数给出的值。

$ ./a.out
Initially, *(p->i)=8 *(q->i)=50
After swap_1, *(p->i)=50 *(q->i)=8

Initially, *(r->i)=8 *(s->i)=50
After swap_2, *(r->i)=50 *(s->i)=8
C 指针 结构 按值调用

评论

0赞 Some programmer dude 1/6/2022
你昨天发布了几乎完全相同的问题,然后删除了它以再次重新发布。永远不要那样做,人们会弄清楚并因此惩罚你。如果您对问题的回答不满意,请对其进行编辑以改进它。并花一些时间实际阅读发布的评论和(可能的)答案。如果您想澄清,请回复评论或答案。
0赞 Some programmer dude 1/6/2022
同时刷新帮助页面,特别是“我可以在这里询问哪些主题?”和“我应该避免问哪些类型的问题?”。请重新参加导览并阅读 如何提出好问题 和这个问题清单

答:

2赞 user16004728 1/6/2022 #1

函数交换指针值,而不是指向值。swap_1

函数交换指向的值,但会产生内存泄漏。swap_2

为了干净地交换指向的值,您可以简单地执行以下操作:

void swap_3(E *x, E *y) {
    int temp;
    temp = *(x->i);
    *(x->i) = *(y->i);
    *(y->i) = temp;
}

评论

0赞 Chris 1/6/2022
无需将 declare 和 initialize 分开。temp
1赞 1/6/2022
@Chris:当然,但我试图让它尽可能接近他/她的原始代码,以便将任何可能的混淆减少到最低限度(即,将注意力集中在实际的更改上,而不是不相关的语义更改上)。
0赞 Chris 1/6/2022
答案是肯定的。这可能适合于关于代码样式的答案末尾的附录。同样,由于 deref 运算符的关联性,将适合使用的地方。*x->i*(x->i)
0赞 noobee 1/6/2022
谢谢你@bbbbbbbbb。我刚刚学习C语言,还想了解两点:(1)是什么原因导致我的swap_2函数内存泄漏?(2)是否也可以使用 swap_1 函数,因为它交换了 r 和 s 结构中元素“i”的地址?再次感谢您抽出时间帮助我更好地理解和学习。
0赞 Some programmer dude 1/6/2022
@noobee没有匹配是导致泄漏的原因,mallocfree
1赞 Some programmer dude 1/6/2022 #2

让我们以函数为例:swap_1

void swap_1(E *x, E *y) {
    int *temp = NULL;
    temp = x->i;
    x->i = y->i;
    y->i = temp;
}

并画出每一步,看看会发生什么。

  • 让我们从

    int *temp = NULL;
    

    然后查看您拥有的所有指针以及它们指向的位置,然后它看起来像这样:

    +------+
    | temp | --> NULL
    +------+
    
    +---+     +---+     +-------------+
    | x | --> | i | --> | a from main |
    +---+     +---+     +-------------+
    
    +---+     +---+     +-------------+
    | y | --> | i | --> | b from main |
    +---+     +---+     +-------------+
    
  • 现在让我们做我们的第一个任务:

    temp = x->i;
    

    看看它如何改变事情:

    +------+
    | temp | ----------\
    +------+           |    +-------------+
                       >--> | a from main |
    +---+     +---+    |    +-------------+
    | x | --> | i | --/
    +---+     +---+ 
    
    +---+     +---+     +-------------+
    | y | --> | i | --> | b from main |
    +---+     +---+     +-------------+
    

    正如你所看到的,你现在有两个指针,都指向同一个位置(函数中的变量)。amain

  • 现在让我们做第二个任务:

    x->i = y->i;
    

    这将改变这样的事情:

    +------+     +-------------+
    | temp | --> | a from main |
    +------+     +-------------+
    
    +---+     +---+
    | x | --> | i | --\ 
    +---+     +---+   |    +-------------+
                      >--> | b from main |
    +---+     +---+   |    +-------------+
    | y | --> | i | --/
    +---+     +---+
    

    同样,您有两个指针都指向同一位置(并且都指向函数中的变量)。x->iy->ibmain

  • 最后是最后一项任务:

    y->i = temp;
    

    完成此赋值后,指针将如下所示:

    +---+     +---+     +-------------+
    | x | --> | i | --> | b from main |
    +---+     +---+     +-------------+
    
    +------+
    | temp | ----------\
    +------+           |    +-------------+
                       >--> | a from main |
    +---+     +---+    |    +-------------+
    | y | --> | i | --/
    +---+     +---+ 
    

由此可以清楚地看出,该函数不会从函数中交换 and 变量的。相反,它会交换指针和 .和 的值仍将相同。swap_1abmainx->iy->iab

要交换 和 的实际值,您需要取消引用指针,并使用普通的非指针类型:abtemp

void swap_1(E *x, E *y)
{
    int temp = *x->i;  // Copy the value from where x->i points
    *x->i = *y->i;     // Copy the value
    *y->i = temp;      // Copy the value again
}

如果将来在使用指针时遇到问题,使用铅笔和纸绘制和重绘变量以及类似于上述内容的指针通常有助于可视化实际发生的情况。我建议你自己尝试一下。

评论

0赞 noobee 1/7/2022
谢谢你的解释。真的很感激。我还有最后一个问题:如果我只想交换存储在 x->i 和 y->i 中的地址(而不是存储在 a 和 b 中的整数值),那么我的swap_1函数是否是一种可接受的方法?我的想法是,如果我只是交换 x->i 和 y->i 的地址,那么我可以使用 *(x->i) 和 *(y->i) 来访问值,而无需实际更改 a 和 b 的值。
0赞 Some programmer dude 1/7/2022
@noobee 如果您只想将指针交换,那么是的,您当前的函数将为此工作。x->iy->iswap_1
0赞 noobee 1/9/2022
感谢大家帮助更好地理解这一点。绘制指针图并在这些图上使用指针地址非常有帮助。我现在对指针的用法有了更好的理解。非常感谢你们所有人的帮助。