在函数调用中被单指针和双指针参数混淆 [英] Confused by single pointer and double pointer arguments in function calls

查看:74
本文介绍了在函数调用中被单指针和双指针参数混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图对C函数中的指针参数有更深入的了解.我编写了一个测试程序,以查看将单个指针与双指针传递给函数然后进行修改之间的区别.

I'm trying to get a deeper understanding on pointer arguments in functions for C. I've written a test program to try to see the difference between passing a single pointer vs a double pointer to a function and then modifying it.

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

I have a program that has two functions. The first function modifyMe1 takes a single pointer as an argument and changes the a property to 7. The second function modifyMe2 takes a double pointer as an argument and changes the a property to 7.

我希望第一个函数modifyMe1将是按值传递",即如果我传递了struct指针,则C将创建它所指向的数据的副本.在使用后者的同时,我正在执行按引用传递",应按原样修改结构.

I expected that the first function modifyMe1, would be "pass-by-value" that is if I passed in my struct pointer, C would create a copy of the data pointed by it. While with the latter, I am doing a "pass-by-reference" which should modify the structure in place.

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

However, when I test this program out, both functions seem to modify the structure in place. I know there is a misunderstanding for me on the nature of pointers are arguments for sure. Can someone help clear this up for me?

谢谢!

这就是我所拥有的:

#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: %d\n", test1->a, test1->b);

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

    modifyMe2(&test1);

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


    free(test1);
    return 0;
}

我的输出是:

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

推荐答案

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

You can pass argument in different ways in C (Captain Obvious, yes).

  1. 按值.然后将其复制到堆栈.因此,函数在函数框架中具有变量的本地副本.对参数的任何更改都不会更改传递的值.就像只读"模式

  1. By value. Then it is copied to stack. So function has local copy of variable in function frame. Any changes to argument do not change passed value. It is like "read only" mode

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

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

  • Pass by pointer. Then copy of address of this variable is passed (so yes, it is still passed by value, but you pass value of address, not of whole argument). So this is like "read and write" mode. As you can access to passed variable through its address, you can change value of this variable outside function.

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

    但是!您仍然无法修改指针.

    But! You still can not modify pointer.

    因此,如果要修改指针,则应将指针传递给指针.就像读写修改"模式一样:

    So if you want to modify pointer, then you should pass pointer to pointer. That is like "read-write modify" mode:

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

    如果那只是指针,那么会发生内存泄漏:

    If that was just pointer then there would be a memory leak:

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

    因为在这里您将新地址分配给该地址的本地副本,并且该参数将在函数完成后销毁.

    because here you assign new address to local copy of address, and this argument would be destroyed after function completion.

    UPD.例如,我们有

    UPD. For example, we have

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

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

    inside function memory is allocated and pointer is assigned to local variable. Caller still keeps old value. After function call we lose address of memory so it can not be released.

    简短的结论:有一个简单的规则-如果需要更改参数,则将指针传递给它.因此,如果要更改指针,请将指针传递给指针.如果要更改双指针,请将指针传递到指针.

    Short conclusion: there is a simple rule - if need to change argument, pass pointer to it. So, if want to change pointer, pass pointer to pointer. If want to change double pointer, pass pointer to pointer to pointer.

    通过指针传递参数也要快得多,因为您不需要复制堆栈上的所有值(当然,如果值大于指向该值的指针,否则可以通过指针传递以只读方式传递)是没有意义的.但这很危险,因为可以在函数内部对其进行修改.因此,您可以使用const关键字来保护定义它的参数

    Passing argument by pointer is also much faster, because you don't need to copy all value on the stack (of course, if value is bigger than pointer to this value, otherwise passing by pointer for read-only is pointless). But it is dangerous, because it could be modified inside function. So you can secure argument defining it with const keyword

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

    当您使用第三方库时,这确实很有帮助:函数签名告诉您函数是否可以修改您的参数.尽管const是可选的,但每次有可能写const关键字都是合适的

    This is really helpful when you work with 3rd party libraries: function signature tells you whether function can modify your argument or not. Though const is optional it is appropriate to write const keyword every time it is possible

    传递数组.通常,还发送数组大小(因此,size_t)作为参数.您将数组作为指针传递.

    Passing array. Usually, one also sends array size (hence, size_t) as argument. You pass array as pointer.

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

    有时候,您可以找到代码,在这些代码中,开发人员将指针发送给对象而不是数组.

    Sometimes you can find code where developer sends pointer to object instead of array, for example

    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);
    }
    

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

    In this case array of one element and pointer to element behave alike (though, they are not the same).

    这篇关于在函数调用中被单指针和双指针参数混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆