1. 第一题
1.1 题目
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};//1
int* ptr = (int*)(&a + 1);//2
printf("%d,%d", *(a + 1), *(ptr - 1));//3
return 0;
}
1.2 分析
1.在内存中创建了数组“a”;
2.“&a”为“a”的地址 ,加一跳过整个数组,指向数组末端。将“&a+1”的类型从“int (*)[5]”强制转化为“int* ”,并赋值给ptr;
3."a+1"中,“a”为首元素地址,加一后指向第二个元素,解引用得到2;“ptr”的类型为“int* ”,减一向前移动一个整形,指向第五个元素,解引用得到5。
1.3 结果
2. 第二题
2.1 题目
#include <stdio.h>
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p的值为0x100000.如下表达式的值分别为多少?
//已知,结构体Test类型的变量大小是32个字节(x64环境)
int main()
{
p = (struct Test*)0x100000;//1
printf("%p\n", p + 0x1);//2
printf("%p\n", (unsigned long)p + 0x1);//3
printf("%p\n", (unsigned int*)p + 0x1);//4
return 0;
}
2.2 分析
1.将“0x100000”这一十六进制数赋值给结构体指针“p”;
2.“p”的类型为“struct Test* ”,加1跳过一个结构体变量(占32个字节),所以“p”的值增加了32,得到“0x100020”;
3.“unsigned long”类型的变量加一,则值直接增加1,得到“0x100001”;
4.“unsigned int* ”类型的变量加一跳过4个字节,得到“0x100004”;
2.3 结果
3.第三题
3.1 题目
#include <stdio.h>
int main()
{
int a[4] = {1, 2, 3, 4};//1
int* ptr1 = (int*)(&a + 1);//2
int* ptr2 = (int*)((int)a + 1);//3
printf("%x,%x", ptr1[-1], *ptr2);//4
return 0;
}
3.2 分析
1.创建了含四个元素的整形数组“a”;
2.“&a”为数组的地址,加一跳过整个数组指向数组末尾;
3.“a”被强制类型转化为“int”类型,加一只跳过一个字节,上方橘色数字是内存中数组“a”四个元素的信息(小端存储),“(int)a+1”指向如图所示的位置;
4.“ptr[-1]”相当于“ *(ptr-1)”,也就是4;“ptr2”的类型为“int* ”,解引用时解析后面四个字节的内容,也就是“00 00 01 00”;
3.3 结果
这段代码似乎只能在x86环境下运行,所以这里没有用vscode,而是用的vs2022。
4. 第四题
4.1 题目
#include <stdio.h>
int main()
{
int a[3][2] = {(0, 1), (2, 3), (4, 5)};//1
int* p;//2
p = a[0];//3
printf("%d", p[0]);//4
return 0;
}
4.2 分析
1.在创建二维数组“a”时,大括号内并不是三个一维数组,而是三个逗号表达式,所以真正存进“a”中的只有“1”,“3”,“5”;
2.创建“int* ”类型变量“p”;
3.“a[0]”是二维数组中第一个数组的数组名,在这里表示第一个数组的首元素地址,也就是将“&a[0][0]”赋值给了“p”;
4.“p[0]”相当于“*(p+0)”,也就是“a[0][0]”;当然,你也可以认为“p”与“a[0]”等效,那么“p[0]”就与“a[0][0]”等效了。
4.3 结果
为什么要分两篇来写呢?
当然是为了蹭流量券啊!建议官方按字数发流量券。