[英]Pointer arithmetic and 2-D array in c?
我是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'
。 但是我认为这种方式不起作用。
请解释编译器如何计算这些地址。
指针算术很好。 你忘了取消引用*temp
,它有char[2]
类型。
将其更改为**temp
,您将获得输出c
。
对于函数参数char temp[][2]
, temp
衰减为指针。 但仅限于第一(外)维度。 所以它实际上是一个指向char
数组[2]
的指针 。
正如您已经假设的那样,递增指针将使其前进到下一个外部索引。
因此,您必须使用(*temp)[0]
或**temp
来获取第一个元素。 **temp
有效,因为*temp
是一个数组本身,所以它衰减到指向内部数组的第一个元素的指针。 第二个(左) *
然后取消引用这个指针: c
。
请注意,虽然它使用与char **temp
相同的语法,但它们根本不同。 指针不是一个数组,在这里,递增temp
只会前进一个指针的大小,这不是你想要的。
请注意,初始化程序最好是根据2维性质:
{ { 'a', 'b' } , { 'c', 'd' } }
这可以确保您获得内部数组的正确值,这是一种很好的做法。 省略非嵌套表单中的值将导致内部数组的序列错误。 当至少启用了推荐警告( -Wall
) 时 ,gcc会警告缺少大括号。
除了当它是的操作数sizeof
或一元&
操作员,或者是一个字符串被用来初始化一个声明另一个数组,类型“的N元件阵列的表达 T
将被转换(“衰变”)”,以“指向T
指针”类型的表达式,表达式的值将是数组中第一个元素的地址。
在main
,函数调用foo(arr)
中的表达式arr
的类型是“2元素数组char
的2元素数组”; 因为它不是sizeof
或一元&
运算符的操作数,所以它“衰变”为类型为“指向2元素char
数组的指针”或char (*)[2]
的表达式。
因此,参数temp
是char (*)[2]
,它指向arr
的第一个元素。 参数声明char temp[][2]
等同于char (*temp)[2]
。 表达式*temp
等同于temp[0]
,并且都具有类型“ char
2元素数组”( char [2]
)。 表达式temp + 1
为您提供下一个2元素char
数组的地址,因此*(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
为我们提供了与 &arr
不同的值。 由于temp被声明为指针而不是数组,因此&temp
为我们提供了指针变量的地址。
图片可能会有所帮助:
+---+
arr: |'a'| arr[0][0] <------------------+ before temp++
+---+ |
|'b'| arr[0][1] |
+---+ |
|'c'| arr[1][0] <--+ after temp++ |
+---+ | |
|'d'| arr[1][1] | |
+---+ | |
... | |
+---+ | |
temp: | |---------------+---------------+
+---+
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.