Ale*_*lex 11 c arrays pointers
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;
}
Run Code Online (Sandbox Code Playgroud)
当我运行上面的代码时,我得到以下输出:
1
210
42
210
Run Code Online (Sandbox Code Playgroud)
为什么输出不是1在每种情况下?
小智 6
好吧,如果我想拆分头发:首先,代码在整个printf()语句中调用整个地方的未定义行为.两个指针的区别在于类型ptrdiff_t,为此,正确的转换说明符%td不是%d.
剩下的只是猜测.假设您的系统是合理的,并且在数字上指针值&arr始终是相同的,无论它转换为何种类型.
现在,(&arr + 1) - &arr当然是1,根据指针算法的规则.(两个指针之间的实际差异是210 * sizeof(int)字节,但这不是学校数学而是指针算术,这就是为什么结果以大小为单位给出sizeof(T),其中T是指针的基本类型.)
然后(char *)(&arr + 1) - (char *)&arr将指针强制转换为char *,并且由于大小char为1,这将打印字节差异; 你在这里有效地欺骗/滥用指针算法.
此外:printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr)减去两个类型的指针int (*)[7][6].这就是arr衰败的原因.当然,7*6 = 42,所以arr + 1和之间的大小差异arr是42个元素.
p但是,它不是指向数组第一个元素的指针,而是指向数组本身的指针.它的类型正确表示为int (*)[5][6][7].现在,如果您使用该类型打印差异,但是您不让编译器通过欺骗指针来进行除法unsigned,那么您将得到5 * 6 * 7,即210.
在(&arr + 1) - &arr:
&arr是5个7个数组的5个数组的数组的地址char.如果我们有一个这些对象的数组而不是一个对象的数组,那么添加一个产生5个7个数组的5个数组的下一个数组的地址char.减去原始地址,&arr产生两个地址之间的差异.根据C标准,此差异表示为两个地址之间的元素数,其中元素类型是指向的对象的类型.由于该类型是由7个7的6个数组组成的数组,char因此两个地址之间的距离是一个元素.换句话说,从距离&arr到(&arr + 1)是一个的6 7个阵列的5个数组的数组char.
在(char *)(&arr + 1) - (char *)&arr:
&arr + 1再次指向7个7个数组的5个数组的下一个数组的指针char.当它转换为a时char *,结果是指向下一个数组的第一个字节的指针.类似地,(char *)&arr是指向第一个数组的第一个字节的指针.然后减去两个指针会产生元素之间的差异.由于这些指针是指针char,因此产生的差异为数量char.所以区别在于7个阵列中5个阵列的阵列中的字节数为6个char,即5•7•6 char或210 char.
在(unsigned)(arr + 1) - (unsigned)arr:
由于arr未与&(或sizeof其他特殊情况)一起使用,因此它将自动从5个7个数组的数组6的数组char转换为指向第一个元素的指针.因此,它是一个指向7个数组6的数组的指针char.然后arr + 1是指向7个6的数组的下一个数组的指针char.转换为此地址时unsigned,您正在使用的C实现中的结果实际上是对象的内存地址.(这很常见,但C标准并不保证,当地址为64位但是unsigned32位时肯定会中断.)同样,(unsigned)arr第一个对象的地址也是如此.减去地址后,结果就是它们之间的距离(以字节为单位).所以不同的是7个7个数组的数组中的字节数char,即7•6个字节或42个字节.注意这种情况下的关键区别:&arr是一个指向由5个7个数组组成的5个数组的数组的指针char,但它arr是一个指向7个数组为6的数组的指针char.
在(unsigned)(p + 1) - (unsigned)p:
p是一个指向由5个7个数组组成的5个数组的数组的指针char.然后p+1是指向下一个数组的指针.转换unsigned为如上所述的行为.减去产生差异的字节,所以它是5个7个数组的5个数组的数组的大小char,所以它再次是210个字节.
作为旁白:
(&arr + 1) - &arr是ptrdiff_t和应该打印的类型%td.
(char *)(&arr + 1) - (char *)&arr是ptrdiff_t和应该打印的类型%td.
(unsigned)(arr + 1) - (unsigned)arr是unsigned int和应该打印的类型%u.
(unsigned)(p + 1) - (unsigned)p是unsigned int和应该打印的类型%u.
注意&arr是完整的三维char数组的地址,而arr指向第一个元素是2维char数组.图中的下图:
0xbf8ce2c6
+------------------+ ?-- arr = 0xbf8ce2c6
| 0xbf8ce2f0 |
| +------------------+ ?-- arr + 1 = 0xbf8ce2f0
| | 0xbf8ce31a | |
| | +------------------+ ?-- arr + 2 = 0xbf8ce31a
| | 0xbf8ce344 | | |
| | | +------------------+ ?-- arr + 3 = 0xbf8ce344
| | 0xbf8ce36e | | | |
| | | | +------------------+ ?-- arr + 4 = 0xbf8ce36e
| | | | | | | | | |
+---|---|---|--|---+ | | | | Each are 7*6, 2-Dimensional
| | | | | | | | Consists Of 42 bytes
+---|---|--|-------+ | | |
| | | | | |
+---|--|-----------+ | |
| | | |
+--|---------------+ |
| |
+------------------+
The diagram show:
1. How a 3-dimensional can be interpreted as series of 2-dimensional arrays
2. Here (arr + i) points to a 2-D array
3. Notice difference between: (arr + i + 1) - (arr + i) = 0x2a = 42, where i = [0, 4]
Run Code Online (Sandbox Code Playgroud)
类型&arr是char(*)[5][7][6]char三维数组的地址[5][7][6].&arr和之间的价值差异&arr + 1是5 * 7 * 6 * sizeof(char)= 210.
因为大小char[5][7][6]是5 * 7 * 6 * sizeof(char).
在您的代码中&arr指向3-D数组和&arry + 1下一个3-D数组(我们的代码中不存在).
在codepade上查看此工作代码:
int main()
{
char arr[5][7][6];
printf(" &arr : %p", &arr);
printf(" &arr+1: %p", &arr + 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
&arr : 0xbf5dd7de
&arr+1: 0xbf5dd8b0
Run Code Online (Sandbox Code Playgroud)
(&arr + 1) - (&arr)= 0xbf5dd8b0 - 0xbf5dd7de= 0xd2= 之间的差异210.
在你的第二个printf:
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
Run Code Online (Sandbox Code Playgroud)
您将类型的地址类型转换char(*)[5][7][6]为plain (char*),并且因为sizeof char[5][7][6]是210两个地址都是210远.(记住sizeof(char) == 1).这就是产出的原因:210
正如我在第一个声明中所说,现在arr是第一个元素的地址,它是一个二维的字符数组.类型arr是char(*)[7][6].现在有一个元素(大小为二维数组6 * 7 * sizeof(char) = 42).
(注意:您可以将三维数组视为一维数组,其中每个元素都是一个二维数组).
在你的第三个printf:
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
Run Code Online (Sandbox Code Playgroud)
您将类型转换为无符号值(但不是地址/指针类型).arr + 1和之间的差异arr是42 * sizeof(char)= 42(等于大小char[7][6]).所以printf语句输出:42.
注意: 您应该读取sizeof(int)== sizeof(void*)?,因为你是对地址进行类型转换.并且此转换尚未完全定义.(我的解释是你的输出和我给出的输出).
int main()
{
char arr[5][7][6];
printf(" arr : %p\n", arr);
printf(" arr+1: %p", arr + 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
arr : 0xbf48367e
arr+1: 0xbf4836a8
Run Code Online (Sandbox Code Playgroud)
取之间的差异(arr + 1) - (arr)= 0xbf4836a8- 0xbf48367e= 0x2a= 42.
最后的printf:
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
Run Code Online (Sandbox Code Playgroud)
只需区分&arr+1和&arr= 210(类似于第二个printf)因为p是指向3-D char数组(= &arr)的指针.而且你将它类型化为值类型(不是指针类型).
此外,(只是为了理解目的添加,我想读者会发现它有用),
让我们学习arr和&arr使用sizeof运算符之间的另一个区别,这将有助于您更深入地理解概念.对于第一次阅读:sizeof运营商
将
sizeof运算符应用于数组标识符时,结果是整个数组的大小,而不是数组标识符表示的指针的大小.
在codepade上查看此工作代码:
int main()
{
char arr[5][7][6];
printf(" Sizeof(&arr) : %lu and value &arr: %p\n", sizeof(&arr), &arr);
printf(" Sizeof(arr) : %lu and value arr : %p\n", sizeof(arr), arr);
printf(" Sizeof(arr[0]): %lu and value a[0]: %p\n",sizeof(arr[0]), arr[0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它的输出:
Sizeof(&arr) : 4 and value &arr: 0xbf4d9eda
Sizeof(arr) : 210 and value arr : 0xbf4d9eda
Sizeof(arr[0]): 42 and value a[0]: 0xbf4d9eda
Run Code Online (Sandbox Code Playgroud)
这里&arr只是一个地址,系统地址是四个字节,这是完整的三维字符数组的地址.
arr是三维数组的名称,sizeof运算符给出的数组的总大小210 = 5 * 7 * 6 * sizeof(char).
正如我在图中所示,arr指向的是第一个二维数组元素.所以因为arr= (arr + 0).现在使用*Dereference运算符at (arr + 0)给出地址的值*(arr + 0) = arr[0].
sizeof(arr[0])给出 42= 7 * 6 * sizeof(char).并且这在概念上证明了三维阵列注意到了二维阵列的阵列.因为上面在我的回答很多时候我写的是:"大小char[5][7][6]是5 * 7 * 6 * sizeof(char)." 所以我在@ codepade下面添加了一个有趣的代码:
int main(){
printf(" Char : %lu \n", sizeof(char));
printf(" Char[5] : %lu \n", sizeof(char[6]));
printf(" Char[5][7] : %lu \n", sizeof(char[7][6]));
printf(" Char[5][7][6]: %lu \n", sizeof(char[5][7][6]));
return 1;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Char : 1
Char[5] : 6
Char[5][7] : 42
Char[5][7][6]: 210
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
251 次 |
| 最近记录: |