C++ 当人们想要在函数中操作指针时,为什么要传入双指针?

C++ 当人们想要在函数中操作指针时,为什么要传入双指针?,c++,optimization,C++,Optimization,当查看代码时,我注意到人们在想要操作指针时会将指针传递给函数 我看到的是这样的事情 void increment_if_J (char ** ptr) { if (**ptr == 'J') ++(*ptr); } 但是,将引用传递给指针不是更有意义吗 void increment_if_J (char * & ptr) { if (*ptr == 'J') ++(ptr); } 这样,您就不必创建额外的变量,也不必思考令人困惑的“指针对指

当查看代码时,我注意到人们在想要操作指针时会将指针传递给函数

我看到的是这样的事情

void increment_if_J (char ** ptr)
{
    if (**ptr == 'J')
       ++(*ptr);
}
但是,将引用传递给指针不是更有意义吗

void increment_if_J (char * & ptr)
{
    if (*ptr == 'J')
       ++(ptr);
}

这样,您就不必创建额外的变量,也不必思考令人困惑的“指针对指针”逻辑来破坏您的大脑。

因为每个C参数的传递都是错误的。在C++中,这是不同的,它有引用。

< p>因为每个C参数传递是。这在C++中是不同的,它有引用。

你用代码< > [C++ ] /代码>和<代码> [C++] < /COD>
  • 在C语言中,答案很简单:没有引用,所以第二种方法不是一种选择

  • 在C++中,两者都是有效的,并且在很大程度上是一种文体选择。有些人可能会觉得第一种方法会让调用站点更清楚,指针可能会被函数修改。有些人可能更喜欢第一种,因为他们习惯于用C进行编码。有些人可能更喜欢第二种,因为您引用了一些原因。等等


您在问题上同时添加了
[c]
[c++]

  • 在C语言中,答案很简单:没有引用,所以第二种方法不是一种选择

  • 在C++中,两者都是有效的,并且在很大程度上是一种文体选择。有些人可能会觉得第一种方法会让调用站点更清楚,指针可能会被函数修改。有些人可能更喜欢第一种,因为他们习惯于用C进行编码。有些人可能更喜欢第二种,因为您引用了一些原因。等等


尽管出于与预先存在的C API代码(无引用)兼容的原因,通常使用双指针传递,但在某些情况下(除了编码样式),函数可能更喜欢直接修改其参数,而不是分配额外的堆栈本地参数:

void increment_if_J(char ** ptr)
{
    // I can use ptr to do some other processing first
    char** original = ptr;
    char other_str[] = "Jenny";
    char* contrivedptr = other_str;
    ptr = &contrivedptr;
    **ptr = 'F'; // other_str is now "Fenny"
    ptr = original;

    if (**ptr == 'J')
        ++(*ptr);
}

void increment_if_J_ref(char * & ptr)
{
    // Can't directly use ptr without modifying the referred memory

    if (*ptr == 'J')
        ++(ptr);
}

int main(){

    char str[] = "Jerry";
    char* ptr = str;
    increment_if_J(&ptr); // ptr points to "erry"

    ptr = str;
    increment_if_J_ref(ptr); // ptr points to "erry"

    return 0;
}

这不是一种“促进创新”的技术,但在特殊内存受限的情况下可能会派上用场。

虽然双指针传递主要是为了与预先存在的C API代码兼容(无参考),但也有一些情况(除了编码样式)函数可能更愿意直接修改其参数,而不是分配额外的堆栈本地参数:

void increment_if_J(char ** ptr)
{
    // I can use ptr to do some other processing first
    char** original = ptr;
    char other_str[] = "Jenny";
    char* contrivedptr = other_str;
    ptr = &contrivedptr;
    **ptr = 'F'; // other_str is now "Fenny"
    ptr = original;

    if (**ptr == 'J')
        ++(*ptr);
}

void increment_if_J_ref(char * & ptr)
{
    // Can't directly use ptr without modifying the referred memory

    if (*ptr == 'J')
        ++(ptr);
}

int main(){

    char str[] = "Jerry";
    char* ptr = str;
    increment_if_J(&ptr); // ptr points to "erry"

    ptr = str;
    increment_if_J_ref(ptr); // ptr points to "erry"

    return 0;
}


这不是一种“促进创新”的技术,但在特殊的内存限制情况下可能会派上用场。

因为这不是C问题,请不要用
[C]
来标记它。我认为这取决于您正在查看的代码。我在双方都看到了很多例子。指向指针版本的指针可能会被更多的C中心编码器所使用,而这些代码并不认为使用引用。您可以考虑<代码> ValuePosithyFijJ(CHAR**PTR)作为旧的C样式。您已经用两种语言标记了这个。您通常更喜欢有引用的语言中的引用,而不是另一种语言中的引用。我会返回一个带有新值的指针<代码>字符*增量(字符*)。因为这不是C问题,请不要用<代码> [C] < /Cord>来标记它。我想这取决于你所看的代码。我在双方都看到了很多例子。指向指针版本的指针可能会被更多的C中心编码器所使用,而这些代码并不认为使用引用。您可以考虑<代码> ValuePosithyFijJ(CHAR**PTR)作为旧的C样式。您已经用两种语言标记了这个。您通常更喜欢有引用的语言中的引用,而不是另一种语言中的引用。我会返回一个带有新值的指针<代码>字符*增量(字符*)。值得注意的是,在<代码> char *和<代码>变体中,引用不能为null,因此可以省略空校验。(引用的指针可能仍然是空的。)在
char**
变量中,您可能需要空检查指针和指向的指针。@cdhowie它可以是空的,但这取决于调用方是否确保它不是空的。@NeilKirk如果引用的地址是空的,那么某个地方有人触发了它。(
static_cast(*static_cast(nullptr))
是UB。)因此它只能在行为未定义的程序中为null,如果我们允许它,那么我们就无法对任何事情进行推理。是的,发生了一些不好的事情,但我认为“引用被神奇地保护不为null”是误导性的。“在定义了行为的程序中保护引用不为null”已经足够好了。同样,如果允许UB进入混合,则会出现更严重的问题。值得注意的是,在
char*&
变量中,引用不能为null,因此可以省略null检查。(不过,引用的指针可能仍然为null。)在
char**
变体中,您可能必须为空检查指针和指向的指针。@cdhowie它可以为空,但这取决于调用方是否确保为空。@NeilKirk如果引用的地址为空,则某个地方有人触发了UB。(
static_cast(*static_cast(nullptr))
为UB。)因此,它只能在行为未定义的程序中为null,如果我们允许,那么我们就不能对任何事情进行推理。是的,发生了一些不好的事情,但我认为“引用被神奇地保护不为null”是误导性的。在定义了行为的程序中,引用被保护不为null“够了。同样,如果你允许UB加入,你会有更严重的问题。