Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 函数参数差异:双指针与2D数组_C_Arrays_Function_Pointers - Fatal编程技术网

C 函数参数差异:双指针与2D数组

C 函数参数差异:双指针与2D数组,c,arrays,function,pointers,C,Arrays,Function,Pointers,请理解,在声明的情况下,以下两行不相等(在分配方面) 但是当这些被用作函数参数时呢 void func1(double** v1) void func2(double v2[3][3]) 除了关于func2中值的数量的提示外,是否存在功能差异 严格来说,double**arr和double arr[3][3]是两种完全不同的类型 double**arr不是数组,它只是指向double的指针。你有 没有更多的信息。您无法事先知道arr是一个双精度数组数组。因此,执行arr[1][2]将意味着“跳

请理解,在声明的情况下,以下两行不相等(在分配方面)

但是当这些被用作函数参数时呢

void func1(double** v1)
void func2(double v2[3][3])

除了关于
func2
中值的数量的提示外,是否存在功能差异

严格来说,
double**arr
double arr[3][3]
是两种完全不同的类型

double**arr
不是数组,它只是指向
double
的指针。你有 没有更多的信息。您无法事先知道
arr
是一个双精度数组数组。因此,执行
arr[1][2]
将意味着“跳过第一个
double
指针
,并将第二个指针作为第三个元素(索引2)的数组取消引用”

因此,
x=arr[1][2]
可以翻译为以下伪代码:

tmp=memory[+sizeof(double*)]
x=内存[+2*sizeof(双精度)]
双arr[3][3]
相反,它是一个恒定大小的数组,可以做更多的假设。它保证在内存中是连续的,执行
arr[1][2]
意味着“跳过3个
double
的第一个数组,然后跳过第二个数组的两个
double
并查看第三个(索引2)”

因此,
x=arr[1][2]
可以翻译为以下伪代码:

x=内存[+(3+2)*sizeof(双精度)]

作为一个实际的例子,考虑下面的程序:

int func1(int** v1) {
    return v1[1][2];
}

int func2(int v2[3][3]) {
    return v2[1][2];
}

int main(void) {
    int const_arr[3][3]; // Values are not important.
    int **double_ptr;    // We don't really run this code!

    func1(const_arr);
    func2(double_ptr);
}
编译时,它会给出以下(非常相关的)警告:

arrayparam.c:在函数“main”中:
arrayparam.c:13:8:警告:从不兼容的指针类型[-Wincompatible指针类型]传递“func1”的参数1
职能1(常数);
^~~~~~~~~
arrayparam.c:1:5:注意:应为“int**”,但参数的类型为“int(*)[3]”
int func1(int**v1){
^~~~~
arrayparam.c:14:8:警告:从不兼容的指针类型[-Wincompatible指针类型]传递“func2”的参数1
func2(双重ptr);
^~~~~~~~~~
arrayparam.c:5:5:注意:应为“int(*)[3]”,但参数的类型为“int**”
int func2(int v2[3][3]){

您可以从生成的程序集中非常清楚地看到,这两个函数执行完全不同的操作,而此程序集代码实际上与我上面编写的伪代码完全相同:

func1()

func2()


您是否尝试同时使用这两个函数并查看会发生什么?将const_arr传递给func2和func1在功能上不是很相似吗?不,不会。您不能这样做,正如您从GCC警告中看到的那样。这将导致
func1()
非常严重的segfault。您的意思是func2将崩溃吗?不,
func1(const_arr)
崩溃。请看我的答案。阅读警告。您不能调用
func1(const\u arr)
,也不能调用
func2(double\u ptr)
int func1(int** v1) {
    return v1[1][2];
}

int func2(int v2[3][3]) {
    return v2[1][2];
}

int main(void) {
    int const_arr[3][3]; // Values are not important.
    int **double_ptr;    // We don't really run this code!

    func1(const_arr);
    func2(double_ptr);
}
664:   48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
668:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8] ; load the array
66c:   48 83 c0 08             add    rax,0x8                 ; go 1*8 = 8 bytes forward (sizeof(int*))
670:   48 8b 00                mov    rax,QWORD PTR [rax]     ; dereference that pointer
673:   8b 40 08                mov    eax,DWORD PTR [rax+0x8] ; go 2*4 = 8 bytes forward (2*sizeof(int)) and take the value there
67c:   48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
680:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8] ; load the array
684:   48 83 c0 0c             add    rax,0xc                 ; go 3*4 = 12 bytes forward
688:   8b 40 08                mov    eax,DWORD PTR [rax+0x8] ; go another 2*4 = 8 bytes forward and take the value there