为什么使用 int** ar 而不是 int* ar?

Why use int** ar and not int* ar?

#include <stdio.h>
#include <stdlib.h>
void input(int **ar, int *n) {
    printf("Number of elements: ");
    scanf("%d", n);
    *ar = (int*)malloc(*n * sizeof(int));
    //*ar = new int[*n];
    for (int i = 0; i < *n; ++i){
        printf("Element %d:", i);
        scanf("%d", &(*ar)[i]);
    }
    return;
}
void output(int *ar, int n) {
    for (int i = 0; i < n; ++i) {
        printf("%5d\n", ar[i]);
    }
    return;
}
int main() {
    int n = 0;
    int *ar = NULL;
    input(&ar, &n);
    output(ar, n);
    free(ar);
    return 0;
}

所以我刚刚在我的大学学习了 C 中的指针。有些我明白,有些我不明白。例如,我不明白为什么 input 函数中的 arint** 而不是 int*。我的意思是我尝试用 int* ar 替换 int** ar 并在 main 函数中删除 int* ar = NULL 中的 * 并且没有编译错误。当我 运行 程序时,一切正常。我输入元素的数量并在这些元素中输入一些值,但是当我在最后一个元素中输入最后一个数字时,我什么也得不到。所以我撤消了一切,程序又正常运行了。

此处使用的指针的一个常见用途是允许函数调用更改其中一个变量的值。

例如,假设您有以下内容:

void
change_num(int num)
{
    num = 6;
}

int
main()
{
    int num = 5;
    change_num(num);
    printf("%i\n", num);

    return 0;
}

这不起作用,因为 change_num 正在更改 numcopy 而不是 num 本身。

相反,您必须将指向 num 的指针传递给函数:

void
change_num(int* num_ptr)
{
    *num_ptr = 6;
}

int
main()
{
    int num = 5;

    change_num(&num);
    printf("%i\n", num);

    return 0;
}

*num_ptr = 6;的意思是,“将num_ptr指向的对象改为6。”

在一般情况下,如果我们想让一个函数改变SomeType类型变量的值,那么我们必须传递一个SomeType*给函数。

在您的例子中,您想要更改 ar 的值,即 int*。现在,它不包含任何内容 (NULL) 的地址,您希望将其更改为包含已分配数组(由 malloc 创建)的值。如果我们将 int* 传递给函数以更改 int 并传递 SomeType* 以更改 SomeType,那么我们必须传递 int** 以更改 int*.

您发布的程序正在执行以下操作(按照下面给定的顺序):

  1. Declare/define 函数中的指针
  2. 在其他函数中为该指针分配内存,并用用户输入填充该内存
  3. 使用另一个函数打印该内存的内容
  4. 释放内存并退出

让您感到困惑的部分是 2。

I don't understand why ar in the input function is an int** and not an int* ....

如果你想在其他函数中为指针分配内存(或者想改变指针,比如,让它指向其他内存或重新分配内存等),你需要访问该指针那个函数,如果你有那个指针的地址,你就可以访问。
这就是为什么这里传递了 ar 指针的地址:

input(&ar, &n);

ar 的地址传递给 input() 函数,并在输入函数中取消引用该地址(即 *ar)将给出 ar 指针(declared/defined 在 main()).
为了更好地理解,我将 input() 函数的 ar 参数重命名为 input_ar:

void input(int *input_ar, int *n) {
    .....
    .....

当从 main() 函数调用 input() 函数时,in-memory 视图将是这样的:

    input_ar       ar
      +-----+       +-----+      
      | 200 | ----> | NULL|
      +-----+       +-----+

[200 is address of ar pointer]

input() 函数中,当您执行以下操作时:

*input_ar = (int*)malloc(*n * sizeof(int));

取消引用 input_ar(即 *input_ar)将得到 ar:

    input_ar      *input_ar (ar)       (newly allocated memory block)
      +-----+            +-----+       +-----+
      | 200 | ---------> | 300 | ----> |     |
      +-----+            +-----+       +-----+

[300 is address of the newly allocated memory block]

因此,通过取消引用 input_ar,可以在 input() 中更改指针 ar

I mean I try to replace int** ar with int* ar and delete the * in int* ar = NULL in the main function and there's no compile error.

请注意,如果您从 main() 中的 ar 声明中删除 *,则 ar 将成为 int 类型的变量,这意味着,它不会是一个指针,而是一个可以保存 int 类型值的变量。如果您在程序中进行此更改,则必须在其他地方进行更改,例如,您在 input() 函数中接受用户输入的方式,output() 函数中的相应更改等。

您没有显示程序,您在从 ar 声明中删除 * 后所做的更改,所以,我将只讨论传递给 [= 的 ar 参数22=]:

这是您可能尝试过的方法:

int ar;

input (&ar, &n);

并在 input() 中:

void input(int *ar, int *n) {
    printf("Number of elements: ");
    scanf("%d", n);
    ar = (int*)malloc(*n * sizeof(int));

    .....

注意ar指针参数是input()函数的局部变量。 当从 main() 函数调用 input() 函数时,ar 将保存 main() 函数的 ar 变量的地址。 如果需要,可以使用 input() 函数中的指针 ar 来更改 ar 变量的值,例如- *ar = 9; 这会将值 9 分配给变量 ar(属于 main())。 in-memory 视图应该是这样的

    ar (of input())          ar (of main())
      +-----+                +-----+      
      | 200 | -------------> |     |
      +-----+                +-----+

[200 is address of ar variable of main()]

但是当你这样做时

ar = (int*)malloc(*n * sizeof(int));

ar 丢失了 main() 函数的 ar 变量的地址,新分配的内存引用被分配给 input() 的指针 ar,即

    ar (of input())          newly allocated memory block
      +-----+                +-----+      
      | 400 | -------------> |     |
      +-----+                +-----+

[400 is address of the newly allocated memory block]

您可以 write/modify 此内存中的内容,但当从 input() 返回时,此内存引用将丢失,因为 input() 未返回任何内容,这将是内存泄漏在你的程序中。