指针的进阶(五)

简介: 指针的进阶(五)

九 指针和数组笔试题解析

(1)代码1展示

1. #include <stdio.h>
2. int main()
3. {
4.  int a[] = { 1,2,3,4 };
5.  printf("%d\n", sizeof(a));//16(整个数组的大小)  数组名a单独放在sizeof内部,计算的是整个数组的大小  4*4=16
6.  printf("%d\n", sizeof(a + 0));//4(首元素地址大小) 数组名没有单独放在sizeof内部,也没有&,所以这里的数组名是指的是数组首元素地址
7.  // a+0 还是数组首元素地址,地址的大小4/8  在VS2019的环境内,是4
8.  printf("%d\n", sizeof(*a));//4(首元素的大小) a表示首元素地址,*a 对首元素地址进行解引用,就是首元素。首元素的大小是int类型是4个字节
9.  printf("%d\n", sizeof(a + 1));//4(第二个元素地址的大小) a表示首元素地址,a+1表示第二个元素的地址,4/8   在VS2019是4
10.   printf("%d\n", sizeof(a[1]));//4(第二个元素的大小) 表示数组的第二个元素2,int类型 4
11.   printf("%d\n", sizeof(&a));//4(整个数组的地址)a表示整个数组的大小,&a 整个数组的地址的大小 4/8  在VS2019是4
12.   printf("%d\n", sizeof(*&a));//16(整个数组的大小)  & 和 *相互抵消,相当于sizeof(a),所以是16;
13.   printf("%d\n", sizeof(&a + 1));//4(地址的大小) &的优先级大于+的优先级 &a(数组的地址) 跨过一个数组的地址,也是地址 4/8   在VS2019是4
14.   printf("%d\n", sizeof(&a[0]));//4  1这个元素的地址  4/8 在VS2019是4
15.   printf("%d\n", sizeof(&a[0] + 1));//4 2 这个元素的地址 4/8 在VS2019是4
16.   return 0;
17. }

(1)数组名是数组首元素地址,但是有两个例外:(1)sizeof(数组名),这里的数组名表示整个数组的大小,sizeof(数组名),计算的是整个数组的大小(单位是字节)(2)&数组名,这里的数组名,也表示整个数组,取出的是整个数组。      除了上面两种特殊情况外,剩下的所有数组名都是数组首元素地址。

(2)代码2展示

1. #include <stdio.h>
2. #include <string.h>
3. int main()
4. {
5.  char arr[] = { 'a','b','c','d','e','f' };
6.  printf("%d\n", sizeof(arr));//6(整个数组的大小)  数组名arr单独放在sizeof内部,计算的是整个数组的大小  1*6=6
7.  printf("%d\n", sizeof(arr + 0));//4(首元素地址大小) 数组名没有单独放在sizeof内部,也没有&,所以这里的数组名是指的是数组首元素地址
8.  // arr+0 还是数组首元素地址,地址的大小4/8  在VS2019的环境内,是4
9.  printf("%d\n", sizeof(*arr));//1
10.   printf("%d\n", sizeof(arr[1]));//1
11.   printf("%d\n", sizeof(&arr));//4/8 在VS2019是4
12.   printf("%d\n", sizeof(&arr + 1));//4/8 在VS2019是4  跳过整个数组的地址
13.   printf("%d\n", sizeof(&arr[0] + 1));//4/8 在VS2019是4  跳过一个元素的地址 第二个元素的地址
14. 
15.   //这个数组有6个元素是毫无疑问的,这个数组的后面和前面放的是什么,我们是不知道的,strlen关注的是\0,有\0才停止。
16.   printf("%d\n", strlen(arr));// arr没有& 没有sizeof内部 所以arr是首元素地址,但是数组中没有\0,计算的时候不知道什么时候停止,所以就是随机值    
17.   printf("%d\n", strlen(arr + 0));//  arr首元素地址,arr+0还是首元素地址,  所以就是随机值
18.   printf("%d\n", strlen(*arr));//err, strlen需要的是一个地址,从这个地址开始向后找字符,直到\0,统计字符个数
19.   //但是*arr是数组首元素,也就是'a',这时传给strlen就是'a'的ASCII值97,strlen函数会把97作为起始地址(违规地址),统计字符串,会形成内存访问冲突
20.   printf("%d\n", strlen(arr[1]));// err 和上一个一样 内存访问冲突
21.   printf("%d\n", strlen(&arr));// 随机值  整个数组的地址,arr代表整个数组,地址的类型是 char(*)[6],不是char*,所以会出现错误,虽然地址指针类型是不同的,
22.   //但是 传参过去,按照strlen的类型开始运行,会出现随机值
23.   printf("%d\n", strlen(&arr + 1));// 跳过整个数组的地址 随机值
24.   printf("%d\n", strlen(&arr[0] + 1));// 第二个元素的地址
25.   return 0;
26. }

strlen 求字符串的长度 关注的就是‘\0’前有多少个字符

sizeof()只关注占用内存空间大小,单位是字节

sizeof 不关注类型

sizeof 是操作符

strlen(const char*)只关注\0的位置,计算的是\0之前出现了多少个字符,

strlen 针对字符串

strlen 是库函数

(3)代码3展示

1. #include <stdio.h>
2. #include <string.h>
3. int main()
4. {
5.  char arr[] = "abcdef";
6.  printf("%d\n", sizeof(arr));//arr代表整个数组 sizeof 计算的是整个数组的大小 ,还有一个\0    7
7.  printf("%d\n", sizeof(arr + 0));//arr首元素地址  4/8  4
8.  printf("%d\n", sizeof(*arr));// arr首元素地址 1
9.  printf("%d\n", sizeof(arr[1]));//首个元素 1
10.   printf("%d\n", sizeof(&arr));// 整个数组的地址    4/8  4
11.   printf("%d\n", sizeof(&arr + 1));//  跨过一个数组的地址  4/8  4
12.   printf("%d\n", sizeof(&arr[0] + 1));//  跨过一个元素的地址  4/8  4
13. 
14.   printf("%d\n", strlen(arr));//arr首元素地址, \0之前的元素  6
15.   printf("%d\n", strlen(arr + 0));//6
16. //printf("%d\n", strlen(*arr));//err
17.   //printf("%d\n", strlen(arr[1]));//err
18.   printf("%d\n", strlen(&arr));//整个数组的地址 地址参数不同 6
19.   printf("%d\n", strlen(&arr + 1));//  跨过整个数组的地址 地址参数不同 随机值
20.   printf("%d\n", strlen(&arr[0] + 1));//跨过一个元素的地址  5
21.   return 0;
22. }

(4)代码4展示

1. #include <stdio.h>
2. #include <string.h>
3. int main()
4. {
5.  char* p = "abcdef";//字符指针,存放'a'的地址
6.  printf("%d\n", sizeof(p));//p是一个指针,sizeof计算的是指针变量的大小 4/8
7.  printf("%d\n", sizeof(p + 1));// b的地址 4/8
8.  printf("%d\n", sizeof(*p));// 字符'a'    1
9.  printf("%d\n", sizeof(p[0]));//p[0]等价于*(p+0)  字符'a'   1
10.   printf("%d\n", sizeof(&p));//二级地址    4/8
11.   printf("%d\n", sizeof(&p + 1));// 二级地址  4/8   指向的是char*的地址,+1跨过一个字符指针(所有元素的地址)(四个字节)(也就是&p这个地址再加上四个字节),就是现在的地址
12.   //例如 数组 &arr + 1,(arr里有3个元素(int)12个字节),那么&arr+1 就是&arr这个地址,再加上12个字节,就是现在的地址
13.   printf("%d\n", sizeof(&p[0] + 1));//字符'b'的地址   4/8
14. 
15.   printf("%d\n", strlen(p));//   6
16.   printf("%d\n", strlen(p + 1));//  5
17.   //printf("%d\n", strlen(*p));// err
18.   //printf("%d\n", strlen(p[0]));//err
19.   printf("%d\n", strlen(&p));// 随机值
20.   printf("%d\n", strlen(&p + 1));//  随机值
21.   printf("%d\n", strlen(&p[0] + 1));//5
22.   return 0;
23. }

sizeof 地址 4/8

strlen 地址 找 \0

(5)代码5展示

1. #include <stdio.h>
2. int main()
3. {
4.  int a[3][4] = { 0 };//三行四列
5.  printf("%d\n", sizeof(a));// 48
6.  printf("%d\n", sizeof(a[0][0]));//4
7.  printf("%d\n", sizeof(a[0]));//a[0]表示第一行数组名,a[0]作为数组名,存放在sizeof里,16
8.  printf("%d\n", sizeof(a[0] + 1));//a[0] 没有取地址,没有放在sizeof内部,表示第一行首元素地址, 表示第二个元素的地址,4/8
9.  printf("%d\n", sizeof(*(a[0] + 1)));//4
10.   printf("%d\n", sizeof(a + 1));//a表示数组首元素地址(也就是第一行的地址),第二行的地址  4/8
11.   printf("%d\n", sizeof(*(a + 1)));// 第二行地址是 &第二行数组名 解引用 是第二行数组名  16
12.   printf("%d\n", sizeof(&a[0] + 1));// a[0]表示第一行的数组名,&第一行的数组名,就是第一行的地址, 表示第二行的地址 4/8
13.   printf("%d\n", sizeof(*(&a[0] + 1)));//第二行的数组名 16
14.   printf("%d\n", sizeof(*a));// 第一行的数组名 16
15.   printf("%d\n", sizeof(a[3]));//感觉是越界了,但是a[3],就不会去访问,就不会去计算,仅仅看类型 第四行的数组名,16
16.   return 0;
17. }

二维数组的数组名,代表二维数组的首元素地址,就是第一行的地址,就是&第一行数组名。

a[i] 第i行数组名

十 指针笔试题

笔试题(1)

1. #include <stdio.h>
2. int main()
3. {
4.  int a[5] = { 1, 2, 3, 4, 5 };
5.  int* ptr = (int*)(&a + 1);
6.  printf("%d,%d", *(a + 1), *(ptr - 1));
7.  return 0;
8. }

2 5

笔试题(2)

1. #include <stdio.h>
2. struct Test
3. {
4.  int Num;
5.  char* pcName;
6.  short sDate;
7.  char cha[2];
8.  short sBa[4];
9. }*p;//p是结构体指针,这个结构体有20个字节 4+4+2+1*2+2*4=20
10. int main()
11. {
12.   p = (struct test*)0x100000;
13.   printf("%p\n", p + 0x1);//指针+1
14.   printf("%p\n", (unsigned long)p + 0x1);//整数+1
15.   printf("%p\n", (unsigned int*)p + 0x1);//指针+1
16.   printf("%x\n", (unsigned long)p + 0x1);
17.   printf("%x\n", (unsigned int*)p + 0x1);
18.   return 0;
19. }//考点 +1 ,加到哪里

指针+1,跨过多少个字节,取决于指针的类型。

%p 以地址的形式打印,不省略

%x 打印16进制,省略0;

笔试题(3)

1. #include <stdio.h>
2. int main()
3. {
4.  int a[4] = { 1, 2, 3, 4 };
5.  int* ptr1 = (int*)(&a + 1);
6.  int* ptr2 = (int*)((int)a + 1);
7.  printf("%x,%x", ptr1[-1], *ptr2);
8.  return 0;
9. }

4  2000000

大小端

笔试题(4)

1. #include <stdio.h>
2. int main()
3. {
4.  int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式 结果为 1  2  3
5.  int* p;
6.  p = a[0];
7.  printf("%d", p[0]);
8.  return 0;
9. }

1

笔试题(5)

1. #include <stdio.h>
2. int main()
3. {
4.  int a[5][5];
5.  int(*p)[4];//p是一个数组指针,指向的是4个元素的数组
6.  p = a;//p和a地址一样
7.  printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);p[4][2]等价于*(*(p+4)+2)
8. //指针p的类型是int(*)[4] p+1,指针+1,跨过指针指向的类型,p+4跨过16*4个字节,解引用后,指针的类型是int类型,+2,跨过4*2个字节。   p[4][2]是这个二维数组的第18个元素   a[4][2]是这个二维数组的第22个元素,指针相减,得到的是中间元素的个数,4,因为是低地址减去高地址,所以是-4,%p打印的是地址(也就是补码)所以是ff ff ff fc
9.  return 0;
10. }

ff ff ff fc (-4的16进制)(补码)          -4    

%p打印的是内存中的补码

两个地址相减,得到的是中间元素的个数,

笔试题(6)

1. #include <stdio.h>
2. int main()
3. {
4.  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
5.  int* ptr1 = (int*)(&aa + 1);
6.  int* ptr2 = (int*)(*(aa + 1));
7.  printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
8.  return 0;
9. }

10 5

笔试题(7)

1. #include <stdio.h>
2. int main()
3. {
4.  char* a[] = { "work","at","alibaba" };//存放字符指针的数组
5.  char** pa = a;//a是数组首元素地址 ,首元素地址里面存放的是w的地址,
6.  pa++;//跳过一个字符指针类型的地址,就是数组第二个元素的地址
7.  printf("%s\n", *pa);//得到a的地址,打印字符串
8.  return 0;
9. }

at

笔试题(8)

1. #include <stdio.h>
2. int main()
3. {
4.  char* c[] = { "ENTER","NEW","POINT","FIRST" };//c存放的是这四个字符串首元素地址
5.  char** cp[] = { c + 3,c + 2,c + 1,c };//存放的是数组c的地址,四个字符存放位置的地址(倒过来)
6.  char*** cpp = cp;//数组cp的首元素地址
7.  printf("%s\n", **++cpp);//前置++,先++,后使用, cpp+1得到的是cp第二个元素的地址,*得到的是
8. //cp第二个元素,第二个元素又是c第三个元素的地址,*得到的是c的第三个元素,%s打印,得到POINT
9.  printf("%s\n", *-- * ++cpp + 3);//在第一个printf的时候,cpp发生了变化,++的优先级大于+的优先级,所以cpp+1得到的是cp的第三个元素的地址,
10. //*的优先级大于+的优先级,解引用后得到cp的第三个元素,是c第二个元素的地址,--的优先级大于+的优先级,--第一个元素的地址,解引用,第一个元素,是字符指针,+3,因为是字符指针,指向的是字符,所以跨越3个字符的地址,来到了E的地址,打印结果为 ER
11.   printf("%s\n", *cpp[-2] + 3);//因为上面两个printf,cpp现在指的是cp的第三个元素的地址,cpp[-2] 等价于 *(cpp-2),得到的是cp的第一个元素,就是c的的第四个元素的地址,*后,得到字符指针F的地址,+3,就是S的地址,打印结果为ST
12.   printf("%s\n", cpp[-1][-1] + 1);//cpp还是cp第三个元素的地址,cpp[-1][-1] 等价于
13. // *(*(cpp-1) - 1),打印结果为 EW(NEW)
14.   return 0;
15. }

指针进阶就到此结束了!!!

相关文章
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
5月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
5月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
5月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
5月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
47 4
|
5月前
指针进阶(3)
指针进阶(3)
41 1
|
5月前
|
C++
指针进阶(1)
指针进阶(1)
43 1
|
5月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
42 2
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0