指针的笔试题目
//深度讨论数组名 int main1() {int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a)); //sizeof内部出现数组名代表是整个数组的大小 //16printf("%d\n", sizeof(a + 0)); //首元素地址+0还是首元素地址 4/8printf("%d\n", sizeof(*a)); //首元素地址进行解引用相当于a[0]是4个字节//*a中的a是数组首元素的地址,* a就是对首元素的地址解引用,找到的就是首元素//首元素的大小就是4个字节printf("%d\n", sizeof(a + 1)); //首元素地址+1 相当于a[1]的地址 是地址就是4/8printf("%d\n", sizeof(a[1])); //第二个元素大小//4printf("%d\n", sizeof(&a)); //取地址数组名,取的是整个数组的地址,是地址就是4/8 printf("%d\n", sizeof(*&a));//&a----->的类型是int(*)[4] &a拿的是数组名的地址,数组指针解引用拿到了这个数组是 //是数组的大小就是16printf("%d\n", sizeof(&a + 1));//取数组名+1相当于跳了一个数组的大小,是地址就是4/8printf("%d\n", sizeof(&a[0]));//取第1个元素的地址 是地址就是4/8printf("%d\n", sizeof(&a[0] + 1)); //取第2个元素的地址 是地址就是4/8return 0; }int main2() {char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));//sizeof内部出现数组名代表是整个数组的大小 //6printf("%d\n", sizeof(arr + 0));//首元素'a'的地址---4/8printf("%d\n", sizeof(*arr)); //'a'的大小/1printf("%d\n", sizeof(arr[1]));//'a'的大小/1printf("%d\n", sizeof(&arr));//取出整个数组的地址是地址就是4/8printf("%d\n", sizeof(&arr + 1));//跳过一个数组的地址,是地址就是4/8printf("%d\n", sizeof(&arr[0] + 1));//'b'的地址是地址就是4/8return 0;} #include <string.h> int main3() {char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));//随机值 因为不知道编译器在哪里放\0printf("%d\n", strlen(arr + 0)); //随机值printf("%d\n", strlen(*arr));//相当于strlen('a')strlen(地址)//err 是一个野指针printf("%d\n", strlen(arr[1]));//野指针printf("%d\n", strlen(&arr));//取数组的地址,数组的地址也是从‘a'的地址开始的 随机值printf("%d\n", strlen(&arr + 1));//取数组名+1跳过了一个数组的地址, 随机值-6printf("%d\n", strlen(&arr[0] + 1)); // 首元素的地址+1相当于 是字符b的地址开始 随机值-1return 0; }int main4() {char arr[] = "abcdef";//[a b c d e f\0]printf("%d\n", sizeof(arr)); //计算的是整个数组的大小,7printf("%d\n", sizeof(arr + 0));//首元素地址 相当于是‘a'的地址 是地址就是4/8printf("%d\n", sizeof(*arr));//’a'元素的大小 1printf("%d\n", sizeof(arr[1]));//1printf("%d\n", sizeof(&arr));//取数组的地址 也是从‘a'的地址开始的 也是 4/8printf("%d\n", sizeof(&arr + 1));//跳了一个数组的地址是地址就是 4/8printf("%d\n", sizeof(&arr[0] + 1)); //相当于是’b'的地址 4/8return 0; } //strlen是求字符串长度的,关注的是字符串中的\0,计算的是\0之前出现的字符的个数 // //strlen是库函数,只针对字符串 // //sizeof只关注占用内存空间的大小,不在乎内存中放的是什么 // //sizeof是操作符 int main5() {char arr[] = "abcdef";//[a b c d e f\0]printf("%d\n", strlen(arr));//6printf("%d\n", strlen(arr + 0));//6//printf("%d\n", strlen(*arr));//err//printf("%d\n", strlen(arr[1]));//errprintf("%d\n", strlen(&arr));//‘a’字符的地址开始 6printf("%d\n", strlen(&arr + 1)); //跳过了\0 从\0后面开始 随机值printf("%d\n", strlen(&arr[0] + 1)); //从'b'字符开始走 5return 0; } int main() {char* p = "abcdef";//[a b c d e f\0]printf("%d\n", sizeof(p));//p指向的是字符a的地址 4/8printf("%d\n", sizeof(p + 1)); //指向的是字符b的地址 4/8//printf("%d\n", sizeof(*p)); //err//printf("%d\n", sizeof(p[0])); //errprintf("%d\n", sizeof(&p));//取出的是一级指针的地址 4/8printf("%d\n", sizeof(&p + 1)); //4/8printf("%d\n", sizeof(&p[0] + 1)); //4/8printf("%d\n", strlen(p)); //p指向的是a的地址 6printf("%d\n", strlen(p + 1)); //p指向的是b的地址 5//printf("%d\n", strlen(*p)); //P找到了a的这个字符 err///printf("%d\n", strlen(p[0])); //errprintf("%d\n", strlen(&p)); //取出的是一级指针的地址 随机printf("%d\n", strlen(&p + 1));//随机printf("%d\n", strlen(&p[0] + 1));//5 //P+1 p指向的是b的地址 return 0; }
为什么strlen(&P)是随机值是因为指向p的那块空间上的地址存储方式不确定,有可能是大端存储,也可能是小段存储
int main()
{int a[3][4] = { 0 };printf("%d\n", sizeof(a));//48printf("%d\n", sizeof(a[0][0]));//4printf("%d\n", sizeof(a[0]));a[0]是第一行这个一维数组的数组名,单独放在sizeof内部,a[0]表示第一个整个这个一维数组//sizeof(a[0])计算的就是第一行的大小 也就是第一行的数组名 16printf("%d\n", sizeof(a[0] + 1)); //没有单独放在sizeof内部,表示的是首元素地址 //也就是第一行这个一维数组的第一个元素的地址--a[0][0]的地址 然后+1 就是第一行第二个元素的地址 4/8printf("%d\n", sizeof(*(a[0] + 1))); //第一行第二个元素的地址进行解引用 也就是arr[0][1]元素的大小 --4printf("%d\n", sizeof(a + 1));// 第一行的地址+1 相当于跳到了第二行的地址 是地址就是4/8printf("%d\n", sizeof(*(a + 1))); //第二行的地址解引用 ---就相当于是第二行的数组名 16printf("%d\n", sizeof(&a[0] + 1));// 对第一行的数组名取地址 相当于是第一行的地址,第一行的地址+1相当于是第二行的地址 4/8printf("%d\n", sizeof(*(&a[0] + 1))); //第二行的地址解引用相当于拿到了第二行的数组名 16printf("%d\n", sizeof(*a)); //第一行地址解引用 拿到了第一行的数组名 16printf("%d\n", sizeof(a[3]));//第三行的数组名 虽然越界了 但是不影响计算它内部的大小 16return 0;
}
1.题目1
取数组的地址说明这个指针是的类型是int(*)[5]的,说明这个指针是数组指针,指针指向这个数组,数组有5个元素,每个元素的类型是int类型
题目的指针是int*类型,说明我们要强制类型转换成int*类型的
2.题目2
这里的p是一个结构体指针
1.结构体指针+1相当于跳过的是一个结构体的大小 已经知道一个结构体的大小是20个字节就相当于跳了20个字节。0x100000+20----ox1000014
2.把p强制类型转换成无符号长整形,,已经知道1,048,576是p转换成无符号长整形的数据,它+1= 048,577
3.把p转换成无符号整形指针类型 +1就相当于跳过一个无符号整形 相当于+4 = 1,048,576+4
3.题目3
取数组的地址说明这个指针是的类型是int(*)[4]的,说明这个指针ptr1是数组指针,指针指向这个数组,数组有4个元素,每个元素的类型是int类型
题目的指针是int*类型,说明我们要强制类型转换成int*类型的
ptr1[-1]是指向的是04 00 00 这块区域的 同理也是00是高地址的 04是低地址的拿出来的时候就是低地址在后面 00 00 00 04 以16进制打印的时候前面的0全部删除掉 就是4了
ptr2: 首先这个a是数组名,数组名是首元素地址,首元素地址+1是跳过一个整形也就是4个字节,题目强制类型转换成了int类型说明现在的a不是地址了是一个整数,它+1就说明加了一个整数
比如1的16进制是 00 00 00 01
在内存是小端存储模式,01是低地址处,----01 00 00 00
a+1强制类型转换成int*类型的指针,所以ptr2就指向了 00 00 00 02这块起始地址。因为 00 00 00 02在内存中是以小端模式存储,拿出来的时候就是02 00 00 00 以16进制打印的时候就是200 00 00
因为·02是高位的地址就应该放在低地址处
4.题目4
首先这个二维数组的元素是以逗号表达式的形式展开,你要明确这个数组里的元素是{1,3,5,0,0,0}p指向了第一行的数组名,此时的数组名表示的一行的地址,数组名没有放在sizeof内部,也没有取地址,说明数组名表示首元素地址 也就是a[0][0]的地址然后解引用就是1了
5.题目5
这里的a作为数组名,它是第一行的地址,它的类型是int(*)[5] ,因为二维数组的数组名代表的是第一行的地址,也就是第一行数组名的地址 一维数组名的地址就需要用一维数组的指针来接受。
这里的p是一个数组指针,它指向的是一个数组,这个数组有4个元素,每个元素的类型是int类型
这里把二维数组的数组名赋给数组指针 类型存在差异,但不影响,只不过是报警告
再来看看 p是一个数组指针 它+1跳过一个数组的大小,这个数组有4个元素,每个元素的类型是int类型,相当于跳了4个整形的大小,p[4][2]可以看成 *( *(p+4)+2)
*(p+4)这个相当于p跳了4个整形的大小 再图可以看出 它跳到了a[3][1]的 地址,然后解引用找到了arr[3]的数组名,就可以访问相当于arr[3][1]~ arr[3][4]这块区域的元素的地址,然后+2跳过二个整形长度指向了arr[3][3]这块地址然后解引用找到了arr[3][3] 这个元素
我们是把p[4][2]看成arr[3][3] ,指针-指针的绝对值是元素之间的个数,他们相差了4个 又因为地址再内存中是从低到高存放的,所以结果是-4
打印地址是打印它在内存中的地址,所以这里不考虑大小端字节序,也不考虑原码补码反码,
再x86的环境下就是FF FF FC 记住打印内存是打印反码的形式打印内存
6.题目6
7.题目7
pa是指向的是a的起始地址
pa++跳到了第二行,对pa解引用找到了a的地址相当于指向了a的地址
pa指向了a,a是一个指针数组pa指向的对象是一个char*类型的,第二*说明pa是一个指针
pa++=pa+1 自然是跳过一个char*类型 也就是4个字节。
int*p 是一个指针,它指向的对象是int类型,所以+跳过了4个字节。
8.题目8
11