我是C的新手并且坚持“如何将多维数组传递给函数”。我明白你必须传递列大小,这样如果你想从a[0][0]
转到a[1][0]
它可以计算一维数组的大小并且可以跳过它。
我写了一个小程序:
#include<stdio.h>
void foo(char[][2]);
int main()
{
char arr[2][2] = {'a','b','c','d'};
foo(arr);
return 0;
}
void foo(char temp[][2])
{
temp++;
printf("%c",*temp);
}
我希望此代码会打印字母c
,因为temp
最初指向'a'
,一旦我们递增它,它将跳过第一个1-d数组并转到第二个1-d数组的第一个元素是'c'
。但是我觉得这种方式不起作用。
请解释编译器如何计算这些地址。
答案 0 :(得分:6)
指针算术很好。您忘记取消引用*temp
,其类型为char[2]
。
将其更改为**temp
,您将获得输出c
。
答案 1 :(得分:3)
对于函数参数char temp[][2]
,temp
衰减到指针。但仅限于第一(外)维度。所以它实际上是指向[2]
的数组char
的指针。
增加指针会将其推进到下一个外部索引,正如您已经假设的那样。
因此,您必须使用(*temp)[0]
或**temp
来获取第一个元素。 **temp
有效,因为*temp
本身就是一个数组,所以它衰减到指向内部数组的第一个元素的指针。第二个(左)*
然后取消引用此指针:c
。
请注意,虽然它使用与char **temp
相同的语法,但它们根本不同。指针不是数组,在这里,递增temp
只会增加指针的大小,这不是你想要的。
请注意,初始化程序最好是根据2维性质:
{ { 'a', 'b' } , { 'c', 'd' } }
这可确保您获得内部数组的正确值,这是一种很好的做法。省略非嵌套表单中的值将导致内部数组的序列错误。启用推荐警告(-Wall
)至少后,gcc会警告错误的大括号。
答案 2 :(得分:3)
除非它是sizeof
或一元&
运算符的操作数,或者是用于初始化声明中的另一个数组的字符串文字,否则表达式为类型&#34; T
&#34;的N元素数组;将被转换(&#34;衰减&#34;)到类型为#34的表达式;指向T
&#34;的指针,并且表达式的值将是该表达式中第一个元素的地址阵列。
在main
中,函数调用arr
中的表达式foo(arr)
的类型为&#34;包含char
&的2元素数组的2元素数组#34 ;;因为它不是sizeof
或一元&
运算符的操作数,所以&#34;衰变&#34;表达式为&#34;指向char
&#34;或char (*)[2]
的2元素数组的指针。
因此,参数temp
是char (*)[2]
类型,它指向arr
的第一个元素。参数声明char temp[][2]
等同于char (*temp)[2]
。表达式*temp
等同于temp[0]
,并且两者都具有char
&#34;的类型&#34; 2元素数组; (char [2]
)。表达式temp + 1
为您提供char
的下一个2元素数组的地址,因此*(temp + 1)
相当于temp[1]
。
这是一张总结所有内容的表格:
Expression Type Decays To Value
---------- ---- --------- -----
arr char [2][2] char (*)[2] &arr[0][0]
*arr char [2] char * arr[0]
&arr char (*)[2][2] n/a &arr[0][0]
arr[i] char [2] char * &arr[i][0]
*arr[i] char n/a arr[i][0]
&arr[i] char (*)[2] n/a &arr[i][0]
arr[i][j] char n/a arr[i][j]
temp char (*)[2] n/a &arr[0][0]
*temp char [2] char * arr[0]
&temp char (**)[2] n/a addr of temp variable
temp[i] char [2] char * &arr[i][0]
*temp[i] char n/a arr[i][0]
&temp[i] char (*)[2] n/a &arr[i][0]
temp[i][j] char n/a arr[i][j]
arr + 1 char [2][2] char (*)[2] &arr[1][0]
*(arr + 1) char [2] char * arr[1]
temp + 1 char (*)[2] n/a &arr[1][0]
*(temp + 1) char [2] char * arr[1]
arr[0][0] char n/a 'a'
arr[0][1] char n/a 'b'
arr[1][0] char n/a 'c'
arr[1][1] char n/a 'd'
**temp char n/a 'a'
*temp[0] char n/a 'a'
temp[0][0] char n/a 'a'
**(temp + 1) char n/a 'c'
*temp[1] char n/a 'c'
temp[1][0] char n/a 'c'
所以,在你的print语句中,你会写
printf("%c", **temp); // temp == &arr[1][0] after temp++
或
printf("%c", *temp[0]); // temp[0] == arr[1] after temp++
或
printf("%c", temp[0][0]); // temp[0][0] == arr[1][0] after temp++
表达式arr
,&arr
,*arr
,arr[0]
,&arr[0]
,*arr[0]
和&arr[0][0]
都会产生相同的值 - arr
的第一个元素的地址(请记住,数组的地址和数组的第一个元素的地址是相同的)。他们的类型不同。
请注意,&temp
为我们提供了与<{1}}不同的值。由于temp被声明为指针而不是数组,&arr
为我们提供了指针变量的地址。
图片可能会有所帮助:
&temp