加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

在函数调用中被单指针和双指针参数混淆

发布时间:2020-12-16 10:53:38 所属栏目:百科 来源:网络整理
导读:我试图更深入地理解C函数中的指针参数.我编写了一个测试程序,试图看到将单个指针传递给一个函数的双指针然后修改它之间的区别. 我有一个有两个功能的程序.第一个函数modifyMe1将单个指针作为参数,并将a属性更改为7.第二个函数modifyMe2将双指针作为参数,并将
我试图更深入地理解C函数中的指针参数.我编写了一个测试程序,试图看到将单个指针传递给一个函数的双指针然后修改它之间的区别.

我有一个有两个功能的程序.第一个函数modifyMe1将单个指针作为参数,并将a属性更改为7.第二个函数modifyMe2将双指针作为参数,并将a属性更改为7.

我预计第一个函数modifyMe1将是“按值传递”,即如果我传入了我的结构指针,C将创建它指向的数据的副本.对于后者,我正在做一个“传递引用”,它应该修改结构.

但是,当我测试这个程序时,两个函数似乎都修改了结构.我知道对于指针的性质我有一个误解是肯定的.有人可以帮我解决这个问题吗?

谢谢!

这是我有的:

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

struct myStructure {
    int a;
    int b;
};

void modifyMe1(struct myStructure *param1) {
    param1->a = 7;
}

void modifyMe2(struct myStructure **param1) {
    (*param1)->a = 7;
}

int main(int argc,char *argv[]) {
    struct myStructure *test1;

    test1 = malloc(sizeof(test1));
    test1->a = 5;
    test1->b = 6;

    modifyMe1(test1);

    printf("a: %d,b: %dn",test1->a,test1->b);

    // set it back to 5
    test1->a = 5;
    printf("reset. a: %d,test1->b);

    modifyMe2(&test1);

    printf("a: %d,test1->b);


    free(test1);
    return 0;
}

我的输出是:

$./a
a: 7,b: 6
reset. a: 5,b: 6
a: 7,b: 6

解决方法

您可以在C中以不同的方式传递参数(Captain Obvious,是).

>按价值计算.然后将其复制到堆栈.因此函数在函数框架中具有变量的局部副本.对参数的任何更改都不会更改传递的值.它就像“只读”模式

void fooByValue(myStructure_t arg) {
    printf("passed by value %d %dn",arg.a,arg.b);
    arg.a = 0;
}

>通过指针.然后传递此变量的地址副本(所以是的,它仍然按值传递,但是传递地址的值,而不是整个参数的值).所以这就像“读写”模式.由于可以通过其地址访问传递的变量,因此可以在函数外部更改此变量的值.

void fooByPtr(myStructure_t *arg) {
    printf("passed by pointer %d %dn",arg->a,arg->b);
    arg->a = 0;
}

但!你仍然无法修改指针.
>因此,如果要修改指针,则应将指针传递给指针.这就像“读写修改”模式:

void fooByDblPtr(myStructure_t **arg) {
    *arg = (myStructure_t*) malloc(sizeof(myStructure_t));
    (*arg)->a = 10;
    (*arg)->b = 20;
}

如果那只是指针那么就会出现内存泄漏:

void fooByDblPtr(myStructure_t *arg) {
    arg = (myStructure_t*) malloc(sizeof(myStructure_t));
    (arg)->a = 10;
    (arg)->b = 20;
}

因为在这里你为地址的本地副本分配新的地址,这个参数将在函数完成后被销毁.

UPD.例如,我们有

void fooByPtr(myStructure_t *arg) {
    printf("addr inside foo before %pn",arg);
    arg = (myStructure_t*) malloc(sizeof(myStructure_t));
    (arg)->a = 10;
    (arg)->b = 20;
    printf("addr inside foo after %pn",arg);
}

void main() {
    myStructure_t *x = NULL;
    x = malloc(sizeof(myStructure_t));
    x->a = 10;
    x->b = 20;
    printf("x addr before = %pn",x);
    fooByPtr(x);
    printf("x addr after = %pn",x);
    free(x);
}

分配内部函数内存并将指针分配给局部变量.来电者仍然保持旧价值.函数调用后我们丢失了内存地址,因此无法释放.

简短的结论:有一个简单的规则 – 如果需要更改参数,则将指针传递给它.所以,如果想要改变指针,则将指针传递给指针.如果想要更改双指针,则将指针传递给指针指针.
>通过指针传递参数也要快得多,因为您不需要复制堆栈上的所有值(当然,如果值大于指向此值的指针,否则通过指针传递给只读是没有意义的).但它很危险,因为它可以在功能内部进行修改.因此,您可以使用const关键字来保护定义它的参数

void constFoo(const myStructure_t *arg) {
    arg->a = 10;    //compilation error
    arg->b = 20;    //compilation error
}

当您使用第三方库时,这非常有用:函数签名告诉您函数是否可以修改您的参数.虽然const是可选的,但每次都可以编写const关键字是合适的
>传递数组.通常,还会将数组大小(因此,size_t)作为参数发送.您将数组作为指针传递.

void foo (int *buf,size_t nbuf) {
    ....
}

例如,有时您可以找到开发人员向对象而不是数组发送指针的代码

void foo (int *buf,size_t size) {
    size_t i;
    for (i = 0; i < size; i++) {
        printf("%d ",buf[i]);
    }
}

int main(int argc,char **argv) {
    int a = 10;
    int buf[1] = { 10 };
    foo(buf,1);
    foo(&a,1);
}

在这种情况下,一个元素的数组和指向元素的指针行为相似(但它们不相同).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读