简体   繁体   English

c中的多维数组

[英]multi dimensional array in c

Please explain the output of first and last printf statements. 请解释第一个和最后一个printf语句的输出。 I think they should give the same output. 我认为他们应该提供相同的输出。

int main()
{
   char arr[5][7][6];
   char (*p)[5][7][6] = &arr;

   printf("%d\n", (&arr + 1) - &arr);
   printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
   printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
   printf("%d\n", (unsigned)(p + 1) - (unsigned)p);

   return 0;
}

Output: 输出:

1
210
42
210

Lets see the memory layout first: 首先让我们看一下内存布局:

char arr[5][7][6]; here arr is a array of arrays of arrays. 这里arr是一个由数组组成的数组。

It will be laid out into memory like following: 它会像下面这样布置到内存中:

+--------------+ 
|              | arr[0]
+--------------+
|              | arr[1]
+--------------+
|              | arr[2]
+--------------+
|              | arr[3]
+--------------+

etc.

Now arr[i] is a array of arrays of char . 现在, arr[i]char数组的数组。

So a[i] will be like 所以a[i]就像

+--------------+  a[i][0]
|              |
+--------------+
|              |  a[i][1]
+--------------+
|              |  a[i][2]
+--------------+
|              |  a[i][3]
+--------------+

etc

Now arr[i][j] is a array of chars . 现在arr[i][j]是一个chars数组。

So 所以

+--------------+ 
|              | arr[i][j][0]
+--------------+
|              | arr[i][j][1]
+--------------+ 
|              | arr[i][j][2]
+--------------+

etc.

Compiler will make an entry in its symbol table with name arr and with the address of its first block and also keep track of the total size (5*6*7 = 210 bytes). 编译器将在符号表中使用名称arr和其第一个块的地址进行输入,并跟踪总大小(5 * 6 * 7 = 210字节)。

Now the expression 现在表达

printf("%d\n", (&arr + 1) - &arr);

Its a pointer arithmetic. 它是一个指针算法。 So it will bound to type of every symbols. 因此它将绑定到每个符号的类型。

Lets see this in action. 让我们来看看这一点。

(gdb) p &arr
$1 = (char (*)[5][7][6]) 0x7fffffffe160

You see the type of arr is pointer char (*)[5][6][7] 您会看到arr的类型是指针char (*)[5][6][7]

In other words its pointer to a array of arrays of arrays. 换句话说,它的指针指向数组的数组。 Pointer arithmetic actually do relates to the type the pointer is pointed to. 指针算术实际上与指针所指向的类型有关。 So its important what is the size of the type. 因此重要的是类型的大小。

(gdb) p sizeof(char [5][7][6])
$2 = 210

So any pointer to the type char [5][6][7] will be incremented or decremented like follows: 因此,指向char [5][6][7]类型的任何指针都将按以下方式递增或递减:

&arr+1 => 0x7fffffffe160 +0xd2 => 0x7fffffffe232

and (&arr + 1) - &arr => 0x7fffffffe232 - 0x7fffffffe160=> 0xd2 (&arr + 1) - &arr => 0x7fffffffe232 - 0x7fffffffe160=> 0xd2

Now it returns actually 0xd2 . 现在,它实际上返回0xd2 but for pointer arithmetic it means 1*sizeof(char [5][7][6]) => 1 但是对于指针算术来说,它意味着1*sizeof(char [5][7][6]) => 1

Pointer arithmetic returns the number of sizeof(type) instead of actual byte offset. 指针算术返回number of sizeof(type)number of sizeof(type)而不是实际的字节偏移量。

You are getting correct result for 您正在得到正确的结果

printf("%d\n", (char *)(&arr + 1) - (char *)&arr);

Because of the casting you are making it a char pointer. 由于进行了强制转换,因此您将其变成了char指针。 So the pointer arithmetic will use unit sizeof(char) which is of 1 byte size. 因此,指针算法将使用1字节大小的unit sizeof(char) And hence the output will be 210. 因此输出将为210。

printf("%d\\n", (unsigned)(arr + 1) - (unsigned)arr);

Here arr in a expression will decay to type char (*)[7][6] So its a pointer to a two dimensional array. 在这里,表达式中的arr将衰减为char (*)[7][6]因此它是指向二维数组的指针。 The type its pointing to has a size 6*7 = 42. Thats what you are getting as result. 其指向的类型的大小为6 * 7 =42。这就是结果。

printf("%d\\n", (unsigned)(p + 1) - (unsigned)p); printf(“%d \\ n”,(unsigned)(p +1)-(unsigned)p);

Here, p+1 - p will result in pointer arithmetic 1 * sizeof(char(*)[5][6][7]) . 在这里, p+1 - p将导致指针算术运算1 * sizeof(char(*)[5][6][7]) So in pointer arithmetic, it should return 1. But because of your casting the results of to unsigned , it will abandon pointer arithmetic and use integer arithmetic. 因此,在指针算术中,它应该返回1。但是由于将结果强制转换为unsigned,它将放弃指针算术,而使用整数算术。 Because of using integer arithmetic, it will treat the pointer values of large numbers, so you will get the actual byte offset. 由于使用整数算法,它将处理大数字的指针值,因此您将获得实际的字节偏移量。

They would print the same result if they were treated as pointers, but in the last printf you're forcing them to be treated as unsigned integers by casting. 如果将它们视为指针,它们将输出相同的结果,但是在最后一个printf您通过强制转换将它们视为无符号整数。 Thus, p + 1 and p are subtracted following integer arithmetic rules, as opposed to pointer arithmetic rules. 因此,与指针算术规则相反,遵循整数算术规则减去p + 1p

EDIT 编辑

To make things a little clearer: 为了使事情更清晰:

  • When you subtract 2 pointers the result is the number of elements between them. 当减去2个指针时,结果就是它们之间的元素数。 In your case there's 1 element between them 在您的情况下,它们之间有1个元素
  • When you cast the pointers to unsigned you're telling the compiler "these are just plain numbers, nothing to see here". 当您将指针转换为unsigned您会告诉编译器“这些只是纯数字,在这里看不到任何东西”。 So the compiler treats the addresses as numbers and just subtracts them. 因此,编译器将地址视为数字,然后将它们相减。

The first takes the address of arr and add one, then subtracts the address, the result is clearly 1. 第一个取arr的地址并加一个,然后减去该地址,结果显然为1。

The last one though, p is a pointer to char [5][7][7] , and using (*p)[x][y][z] can be though of as p[0][x][y][z] . 但是,最后一个p是指向char [5][7][7]的指针,使用(*p)[x][y][z]可以作为p[0][x][y][z] So (p + 1) could be thought of as p[1] , which is 210 ( 5 * 7 * 6 ) bytes away from p . 因此(p + 1)可以认为是p[1] ,它与p相距210( 5 * 7 * 6 )个字节。

If you did (((unsigned) p) + 1) - ((unsigned) p) then that would be 1 . 如果您做了(((unsigned) p) + 1) - ((unsigned) p) ,那将是1

the distance between the adresses is 1 element or 210 bytes 地址之间的距离为1个元素或210个字节

The first print prints the number of elements The last - the number of bytes 第一个打印输出元素的数量最后一个-字节数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM