大家好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在
CSDN
这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!
目录
那接下来就让我们开始遨游在知识的海洋!
题集
(1)指针笔试题1
判断代码运行结果
#include<stdio.h>
#include<string.h>
int main() {
char arr[] = "abcd";
//char arr[] = {'a', 'b', 'c', 'd', '\0'}
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0 ));
printf("%d\n", sizeof (*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d", strlen (*arr));
printf("%d", strlen(arr[1]));
printf("%d\n", strlen (&arr));
printf("%d\n", strlen (&arr + 1));
printf("%d\n", strlen (&arr[0] + 1));
return 0;
}
建议思考写下自己的答案再看后文进行核对与理解
答案 | 解析 |
---|---|
5 | sizeof() 内仅有arr (数组名), arr 代表整个数组,所以sizeof计算的是整个数组的大小——5(单位:字节) |
4/8 | 除了仅有arr或&arr 中arr 代表的是整个数组,其他arr 代表的都是数组首元素的地址,地址的大小就是4/8(至于4/8取决于32位机器或64位机器) |
1 | *arr 就是数组首元素'a' (int),大小为1 |
1 | arr[1] == *(arr + 1) ,就是数组的第二个元素,大小为1 |
4/8 | &arr 中的arr 代表的是整个数组,所以&arr 代表的是整个数组的地址,大小就是4/8 |
4/8 | &arr + 1 中的arr 代表的是整个数组,所以&arr + 1 代表的是整个数组后的和数组一样大小的连续元素的地址,大小就是4/8 |
4/8 | 第二个元素的地址 |
4 | strlen(arr) 中arr 代表的是数组首元素的地址,所以strlen() 从数组首元素开始数到至’\0’,结果就为:4 |
4 | strlen(arr+0) 中arr 代表的是数组首元素的地址,所以strlen() 从数组首元素开始数至’\0’,结果就为:4 |
非法访问 | *arr 表示数组首元素,而strlen() 要的是地址,所以非法访问 |
非法访问 | 同上 |
4 | &arr 取出了整个数组的地址,就数整个数组,结果就为:4 |
随机 | &arr + 1 就跳过了整个数组,不知道什么时候出现’\0’,也不知道任何元素的信息,所以打印的是个随机数 |
3 | &arr[0] + 1 就跳过了首元素,结果就为:3 |
考察:一维数组的数组名——特殊与一般
涉及:一维数组,strlen(),sizeof()。
(2)指针笔试题2
判断代码运行结果
#include<stdio.h>
#include<string.h>
int main() {
char* p = "abcd";
//这个代码的意思:把首元素的地址(a的地址)放到指针变量p中
//p就相当于一般的arr(除了两种特殊情况除外)(首元素的地址)
printf("%d\n", sizeof(p)); //地址的大小就是4/8(字节)(至于4/8取决于32位机器或64位机器)
printf("%d\n", sizeof(p + 0 )); //同上
printf("%d\n", sizeof (*p)); //*p就是数组首元素'a'(char),大小为1(字节)
printf("%d\n", sizeof(p[1])); //p[1] == *(p + 1),就是数组的第二个元素,大小为1(字节)
printf("%d\n", sizeof(&p)); //&p中的p代表的是数组首元素的地址,所以&p代表的是存储指针变量p的地址,大小就是4/8
printf("%d\n", sizeof(&p + 1)); //&p + 1中的p代表的是数组首元素,所以&p + 1代表的是存储指针变量p的地址处后一位的地址,大小就是4/8
printf("%d\n", sizeof(&p[0] + 1)); //b的地址,大小就是4/8
printf("%d\n", strlen(p)); //strlen(p)中p代表的是数组首元素的地址,所以strlen函数从数组首元素开始数至'\0',结果就为:4
printf("%d\n", strlen(p + 0)); //strlen(p + 0)中p代表的是数组首元素的地址,所以strlen函数从数组首元素开始数至'\0',结果就为:4
//printf("%d", strlen (*p)); //*p表示数组首元素,而strlen函数要的是地址,所以非法访问
//printf("%d", strlen(p[1])); //同上
printf("%d\n", strlen (&p)); //&p取出了数组首元素的地址的地址,不知道什么时候出现'\0',也不知道任何元素的信息,所以打印的是个随机数
printf("%d\n", strlen (&p + 1)); //&p + 1 就跳过了整个数组,不知道什么时候出现'\0',也不知道任何元素的信息,所以打印的是个随机数
printf("%d\n", strlen (&p[0] + 1)); //&p[0] + 1 就跳过了首元素,结果就为:3
return 0;
}
考察:字符指针——把首元素的地址(a的地址)放到指针变量p中
涉及:字符指针,strlen()。
(3)指针笔试题3
判断代码运行结果
#include<stdio.h>
struct test {
int Num;
char* pcname;
short sDate;
char cha[2];
short sBa[4];
}* p;
//假设 * p = 0x00000000;
//已知结构体变量test的大小为20字节;
int main() {
printf("%p\n", p + 1);
//指针加1跳过整个指针权限的内容(步长)(解引用权限),所以这里跳过了整个结构体变量,也就是20个字节,结果用十六进制表示就是00000014
printf("%u\n", (unsigned long)p + 1);
//先把结构体指针变量p强转成无符号长整型变量,再加1就是让一个整型变量加1,结果就是加1,用十进制表示就是1
printf("%p\n", (unsigned int*)p + 1);
//先把结构体指针变量p强转成整型指针变量,再加1就是让一个整型指针变量加1,指针加1跳过整个权限的内容,所以这里跳过了整个整型变量,也就是4个字节,结果用十六进制表示就是00000004
}
考察:指针加1的意义,是跳过一个步长的地址
涉及:结构体指针,基本指针。
(4)指针笔试题4
判断代码运行结果
//x86,小端
#include<stdio.h>
int main() {
int a[4] = { 1, 2, 3, 4 };
int* p = (int*)(&a + 1);
int* p1 = (int*)((int)(a + 1) + 1); //如果我们定义一个:int* pa = a; 则a + 1就等价于*(pa + 1)
printf("%x\n", p[-1]);
//1.p[-1] == *(p - 1),因为p的类型为int*,所以p-1就是向前挪动一个整型(4个字节)的长度,指向了第4个元素的第一个字节的最左端
//2.再进行解引用,根据p的访问权限可知从当前位置向后访问一个整型(4个字节),就得到了数组的第4个元素——4
//3.又因为%x是用来打印十六位进制数且会去掉前面的0,所以打印就是4
printf("%x\n", * p1);
//1.a + 1:
//低地址 高地址//低地址 高地址
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
//地址设为:00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f //00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
//指针位置:pa --> pa
//2.(int)(a + 1): 把 地址04 强转成一个大小等于 04 的整型数据
//3.(int)(a + 1) + 1:一个整型数据加1,就是数值加1,此时((int)(a + 1) + 1)就得到了一个数值大小为 05 的整型数据
//4.((int*)((int)(a + 1) + 1)):把数值大小为 05 的整型数据强转为 地址05
//5.int* p1 = (int*)((int)(a + 1) + 1):把上面得到的 05的地址 赋给 类型为int*的 整形指针变量p1
//6.printf("%x\n", * p1):再进行解引用,根据p的访问权限可知从当前位置向后访问一个整型(4个字节),就得到了00 00 00 03(小端存储),转换为03 00 00 00(原值)(小端存储是以字节为单位的)
//7.又因为%x是用来打印十六位进制数且会去掉前面的0,所以打印就是3000000
return 0;
}
考察并涉及:小端存储,%x的作用,指针运算。
(5)指针笔试题5
判断代码运行结果
#include<stdio.h>
int main() {
int arr[] = { 1, 2, 3, 4 };
int* p = (int*)(&arr + 1);
printf("%d\n", *(p - 1));
//没什么好讲的
printf("%d\n", *(arr + 1));
//同上
return 0;
}
考察并涉及:一维数组数组名。
(6)指针笔试题6
判断代码运行结果
#include<stdio.h>
int main() {
int arr[2][3] = { (1, 2), (3, 4), (5, 6)};
//逗号表达式的值就是','右边的表达式的结果(但要注意:','左边的表达式也会执行,且是先执行的)
//所以该二维数组的元素为://2 4
//6 0
//0 0
int* p;
p = arr[0];
printf("%d\n", p[1]);
//两种理解p[1]的方法
//1.用数组的格式理解:p = arr[0],则p[1] = arr[0][1] = 4;
//2.用数组的本质理解:arr[0]作为二维数组的第一行的数组元素的数组名,代表的是数组第一行的首元素的地址,即——&arr[0][0],
//p[1] == *(p + 1) == *(&arr[0][0] + 1) == 4
return 0;
}
考查并涉及:指针与二维数组的关系和逗号表达式的作用。
(7)指针笔试题7
判断代码运行结果
#include<stdio.h>
int main() {
int arr[5][5];
//数组元素:|0 0 0 0 0 | 0 0 0 0 0 | 0 0 0 0 0 | 0 0 0 0 0 | 0 0 0 0 0 |
// arr[0] arr[1] arr[2] arr[3] arr[4]
//地址设为:|0 1 2 3 4 | 5 6 7 8 9 | a b c d e | f 0 1 2 3 | 4 5 6 7 8 |
int(*p)[4] = (int(*)[4])arr;
//arr作为二维数组的数组名,类型为:int(*)[5],与数组指针变量p(类型为:int(*)[4])类型基本一致,所以强转之后可以和数组名一样理解
printf("%p,%d\n", &p[4][2] - &arr[4][2], &p[4][2] - &arr[4][2]);
//以p为二维数组的数组名的二维数组:
// 元素:| 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0
// p[0] p[1] p[2] p[3] p[4] p[5] p[6]
//地址设为:| 0 1 2 3 | 4 5 6 7 | 8 9 a b | c d e f | 0 1 2 3 | 4 5 6 7 | 8
//所以 &p[4][2] - &arr[4][2] == 12 - 16 == -4,再根据占位符的功能打印的结果为:FFFFFFFC(十六进制),-4(十进制)
return 0;
}
考察:%p打印的是无符号十六进制的地址值
涉及:二维数组,占位符%p,数组指针。
(8)指针笔试题8
判断代码运行结果
#include<stdio.h>
int main() {
char* arr[3] = { "hello", "world", "bite" };
//arr[0] == &'h' , arr[1] == &'w', arr[2] == &'b'
//即数组元素:&'h'| &'w' | &'b'
//元素名: arr[0]|arr[1]|arr[2]
char** pa = arr;
pa++;
printf("%s\n", *pa);
return 0;
}
考查:字符指针在接收字符串时,接受的是字符串的首元素的地址
涉及:指针数组,占位符%s。
(9)指针笔试题9
判断代码运行结果
#include<stdio.h>
int main(){
char* c[4] = { "hello", "world", "bite", "pengge" };
//一级字符指针数组c:
// 数组元素值:| &'h'| &'w'| &'b'| &'p'|
// 元素类型:|char*|char*|char*|char*|
// 元素意义:|指向"hello"的指针(一开始指向'h')|指向"world"的指针(一开始指向'w')|指向"bite"的指针(一开始指向'b')|指向"pengge"的指针(一开始指向'p')
// 元素名:| c[0]| c[1]| c[2]| c[3]|
// 地址设为: 0 1 2 3
char** cp[4] = {c + 3, c + 2, c + 1, c};
//二级字符指针数组cp:
// 数组元素:| 3 | 2 | 1 | 0 |
// 元素名:|cp[0]|cp[1]|cp[2]|cp[3]|
// 地址设为: a b c d
char*** cpp = cp;
// *cpp == &cp[0] == a
printf("%s\n", **++cpp);
//都只能先从cpp开始分析:
//1.++cpp:cpp先自增1——*cpp = a + 1 == b;
//2.**(++cpp):两次解引用——(1)*(++cpp) == b --> (2)**(++cpp) == 2;
//3.%s的作用:从所给地址开始,一直打印字符至'\0'处,所以打印的结果为:bite
printf("%s\n", *-- *++cpp + 3);
//1.++cpp:cpp再自增1——*cpp = b + 1 == c;
//2.*++cpp:解引用——*cpp == c;
//3.-- *++cpp:c自减1——*c = 1 - 1 ==0;
//4.*-- *++cpp:解引用——*c == 0;
//5.*-- *++cpp + 3:一级字符指针 + 3——*0 = 'h' + 3 == 'l'(临时,不是真的加);
//6.打印结果为:lo
printf("%s\n", *cpp[-2] + 3);
//1.cpp[-2]:cpp指向的值先减2再解引用——(1)cpp - 2——*cpp = c - 2 == a(临时,不是真的加);(2)*(cpp - 2)——*(cpp - 2) = a;
//2.*cpp[-2]:再解引用——**(cpp - 2) == *a == 3;
//3.*cpp[-2] + 3:一级字符指针 + 3——*3 = 'p' + 3 =='g'(临时,不是真的加);
//4.打印结果为:gge
printf("%s\n", cpp[-1][-1] + 1);
//1.cpp[-1]:cpp指向的值先减1再解引用——(1)cpp - 1——*cpp = c - 1 == b(临时,不是真的加);(2)*(cpp - 2)——*(cpp - 2) = b;
//2.cpp[-1][-1]:b指向的值先减1再解引用——(1)b - 1——*b = 2 - 1 == 1(临时,不是真的加);(2)*1——*1 = 'w';
//3.cpp[-1][-1] + 1:一级字符指针 + 1——*1 = 'w' + 1 == 'o'(临时,不是真的加);
//4.打印为:orld
return 0;
}
考察:操作符的优先级只在操作数的相邻位置才考虑;++ 和-- 会真实改变变量存的数据
涉及:二级指针,操作符++和–,解引用。