引用调用和值调用如何作用于多维指针数组?

问题描述

谁能解释一下为什么我不需要 -> int ***zd 在 init 函数中?这不是按值调用吗,当我想打印它时不应该保留初始化吗?还是指针自动通过引用调用? 我很想了解这究竟是如何工作的,所以如果有人能帮助我,我将不胜感激!

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


void initZD(int **zd,int width,int height){
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            zd[i][j] = rand() % 10;
        }
    }
    return;
}
void printZD(int **zd,int breite,int hoehe){
for(int i = 0; i < breite; i++){
    for(int j = 0; j < hoehe; j++){
        printf("%d\t",zd[i][j]);
    }
    printf("\n");
}
}

int main(){

int **zd = NULL;
int width,heigth;

printf("Width: ");
scanf("%d",&width);
printf("Heigth: ");
scanf("%d",&heigth);

//zd = realloc(*zd,breite*sizeof(int));
//zd = calloc(breite,sizeof(int));
zd = malloc(width*sizeof(int));


for(int i = 0; i < width; i++){
//zd[i] = realloc(*zd,hoehe*sizeof(int));
//zd[i] = calloc(hoehe,sizeof(int));
zd[i] = malloc(heigth*sizeof(int));
}

initZD(zd,width,heigth);

printZD(zd,heigth);


free(zd);

for(int x = 0; x < width; x++){
    free(zd[x]);
}

return 0;
}

解决方法

initzD 不需要 zd 的地址,因为它不会改变 zd。它改变了通过 zd 指向的事物(特别是由 zd 指向的指针所指向的事物)。

要改变这些东西,它需要它们的地址,它有它们的地址,因为它们是由 zd 指向的指针指向的。 (一般情况下,指针只指向一些int中的第一个,但zd[i][j]中的下标运算符进行指针运算以计算后续元素的地址。)

,

参数不需要定义为 int ***zd,因为您没有修改 zd 函数中指针 main 的值。您只是取消引用它以修改它指向的值。

如果 zd 未初始化,那么您必须向它传递一个指针,以便该函数可以执行当前在 main 中发生的内存分配。

,

您的函数 initZD 不会更改按值传递的指针 int **zd。它甚至不会改变 zd 指向的指针数组的值,而是只改变那些指针指向的值。

int **zd = NULL; 中的指针 mainmain 中被修改只是因为您在那里分配了内存

zd = malloc(width*sizeof(int));

如果要在函数内部分配内存,则必须将指针的地址传递给 initZD

您的代码包含一个错误:在 main 中,您先调用 free(zd),然后再使用它free 循环中的 free(zd[x]) 其他内存。这是未定义的行为。

需要通过引用传递指针的示例,即传递指针的地址:

void initZD(int ***zd,int width,int height){

    *zd = malloc(width*sizeof(int));

    for(int i = 0; i < width; i++){
        (*zd)[i] = malloc(heigth*sizeof(int));
    }
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            (*zd)[i][j] = rand() % 10;
        }
    }
    return;
}

/* ... */

int main(){

    int **zd = NULL;
    int width,heigth;

    printf("Width: ");
    scanf("%d",&width);
    printf("Heigth: ");
    scanf("%d",&heigth);


    initZD(&zd,width,heigth);

    printZD(zd,heigth);

    for(int x = 0; x < width; x++){
        free(zd[x]);
    }

    /* NOTE you must not free this pointer before the loop above */
    free(zd);

    return 0;
}
,

按值调用意味着将变量的副本传递给函数,而通过引用调用意味着传递变量本身的地址。

这意味着被调用函数中的操作所做的更改将反映在调用函数中。 C 中的数组是通过引用传递的(默认情况下),就像您将数组变量传递给函数一样,该函数实际上是指向数组第一个元素的指针。

当你写 int ** 时,它实际上意味着你指向一个指向元素的地址(因此是 **)。因此,如果要访问数组的整数元素,则需要取消引用两次。对于这里的情况:

zd:它是指向二维数组1st行的指针

zd + i:它是指向二维数组的ith行的指针

*(zd + i)/ zd[i]:取消引用 zd + i 以给出 ith 行的基本元素的地址。

类似地,zd[i][j]j 添加到 ith 行的底部并取消引用它以给出 ith 行和 jth 列的元素的值.

这里的加法规则由指针算术控制,这意味着由于整数占用 4 个字节的数据,如果内存是字节组织的,则指向整数的指针在增加 1 时将指向它之前指向的指针前 4 个单位。