指针数组,数组指针---更深入理解指针数组,数组指针

目录

一维数组(sizeof)

字符数组(sizeof/strlen)

字符指针(sizeof/strlen)

二维数组(sizeof)


操作符---sizeof,用于计算所占内存空间的大小,单位字节。

库函数---strlen,求字符串长度,原理是从首个地址开始统计到\0的字符个数。

(strlen,原理是从接收到的地址开始,一直前进直到找到\0,计算到\0前的字符串长度。如果没有输入正确的地址,或根本不是地址,strlen就会找到那个地方,开始前进找\0,有时是随机值,也有可能会直接报错)

-----------------------------------------------------------------------------------------------------------------------------

数组名有两种情况是表示整个数组

1.sizeof(数组名),数组名表示整个数组,用于计算数组的大小(字节),一定要是单个数组名在sizeof 里才是。

2.&数组名,数组名表示整个地址,取的是整个数组的地址。

除此之外,所有数组名都是首元素地址。

--------------------------------------------------------------------------------------------------------------------------------

虽然整个数组的地址从结果上来看和数组首元素地址是一样的,但是还是要区分开来,否则在一些地方就无法深入分析。

一维数组(sizeof)

已知:

int a[] = {1,2,3,4};

尝试写出以下式子会打印出什么值,原理是什么。

 1.printf("%d\n",sizeof(a));
 2.printf("%d\n",sizeof(a+0));
 3.printf("%d\n",sizeof(*a));
 4.printf("%d\n",sizeof(a+1));
 5.printf("%d\n",sizeof(a[1]));
 6.printf("%d\n",sizeof(&a));
 7.printf("%d\n",sizeof(*&a));
 8.printf("%d\n",sizeof(&a+1));

 1.sizeof(数组名),表示计算整个数组的所占空间的大小。int 类型是4个字节,数组a里有4个元素,所以打印结果是4*4=16。

2.这里相较于前一个,不是单独一个数组名在sizeof里,所以不是求数组大小。此处a作为数组首元素地址,地址+0,就还是首元素地址。地址也就是指针的大小是4/8字节。打印结果是4/8(指针在32位下是4字节,64位是8字节,与指针类型无关)

3.a是数组首元素地址,*a就是对指针解引用(指针就是地址,对地址也可以解引用),得到的就是数组首元素。数组首元素类型是int,大小4字节,打印4

4.a+1和a+0是一样的,a+1就是数组首元素地址 +1,(指针类型是int*,所以移动4个字节,就是移到数组第二个元素),求的是数组第二个元素地址的大小,打印4/8。

5.a[1]就是数组第二个元素,求第二个元素的大小。打印4

6.&a取的是数组a的整个数组的地址,整个数组的地址也是地址,所以打印4/8 。

7.&a然后再解引用,&a是整个数组的地址,类型是 int*()[4],所以解引用得到是数组a,求数组a的大小,打印16

从这个整个数组地址的类型可以看出,虽然整个数组的地址和单单首元素地址是相同的,但是在一些地方也是有差别的,这里就体现在解引用的访问范围上。

8.&a是整个数组的地址,(类型是int(*)[4]),所以&a+1,就是指针向后移动一整个数组的距离。但因为还是指针,所以打印4/8

字符数组(sizeof/strlen)

已知创建了个字符数组

char arr[] = {'a','b','c','d','e','f'};

这个数组元素类型是char,元素个数是6。

分析以下式子的值

1.printf("%d\n", sizeof(arr));
2.printf("%d\n", sizeof(arr+0));
3.printf("%d\n", sizeof(*arr));
4.printf("%d\n", sizeof(arr[1]));
5.printf("%d\n", sizeof(&arr));
6.printf("%d\n", sizeof(&arr+1));
7.printf("%d\n", sizeof(&arr[0]+1));

1.但一个数组名arr,就是求数组的大小,char类型大小是1字节,所以整个数组的大小是6

2.arr+0就是首元素的地址,指针大小是4/8

3.arr是首元素地址,对首元素地址解引用就是得到首元素,首元素大小是1

4.arr[1],就是首元素,大小是1

5.&arr是取整个数组的地址,指针大小为4/8

6.&arr+1,指针指向整个数组后一位,指针大小4/8

7.&arr[0]是取首元素地址,+1也就是第二个元素的地址(指针类型是char*),大小4/8

1.printf("%d\n", strlen(arr));
2.printf("%d\n", strlen(arr+0));
3.printf("%d\n", strlen(*arr));
4.printf("%d\n", strlen(arr[1]));
5.printf("%d\n", strlen(&arr));
6.printf("%d\n", strlen(&arr+1));
7.printf("%d\n", strlen(&arr[0]+1));

1.由于strlen的计算原理是从首个元素一直往下,直到找到\0停止,计算\0之前的字符个数。arr,是指数组首元素地址。这个字符函数每个元素都是明确的,没有\0,所以strlen无法计算,得出的值是随机值。(看顺着地址找下去什么时候找到\0,也就是0,什么时候停下来。

2.arr+0是函数首元素地址,strlen从首元素地址往下找,同上,无法找到,是随机值。

3.*arr是对首元素地址进行解引用,得到的是首元素。但是strlen接收的必须是地址,所以这个是报错。

4.arr[1]是首元素吗,同理上一个,是错误的。

5.&arr,是取整个数组的地址,在strlen任然是从第一个元素地址处开始往后找,是随机值

6.&arr+1,是跳过整个数组,指向数组后一格的地址。是随机值

7.&arr[0]+1,取数组首元素地址,再+1就是第二个元素的地址,随机值。

char arr[] = "abcdef";

在数组内放字符串,字符串结尾有\0(\0是字符串结束的标志)

等价于==>[a b c d e f \0]  7个元素

1.printf("%d\n", sizeof(arr));
2.printf("%d\n", sizeof(arr+0));
3.printf("%d\n", sizeof(*arr));
4.printf("%d\n", sizeof(arr[1]));
5.printf("%d\n", sizeof(&arr));
6.printf("%d\n", sizeof(&arr+1));
7.printf("%d\n", sizeof(&arr[0]+1));

1.arr单独在sizeof内,求的是数组大小,元素类型是char大小1字节,元素个数7,打印7

2.arr+0,是首元素地址,地址大小4/8

3.*arr是对数组首元素地址解引用,就是数组首元素'a',大小是1字节

4.arr[1]也是数组首元素'a',大小1字节

5.&arr取整个数组的地址,指针大小4/8

6.&arr+1是指向数组后一格的地址,指针大小4/8

7.&arr[0]+1,首元素地址+1就是第二个元素地址,指针大小4/8

1.printf("%d\n", strlen(arr));
2.printf("%d\n", strlen(arr+0));
3.printf("%d\n", strlen(*arr));
4.printf("%d\n", strlen(arr[1]));
5.printf("%d\n", strlen(&arr));
6.printf("%d\n", strlen(&arr+1));
7.printf("%d\n", strlen(&arr[0]+1));

1.arr是首元素地址,数组最后是有\0,结果是6(字符串长度是6)

2.arr+0还是首元素地址,6

3.*arr是对首元素地址进行解引用,得到数组首元素,因为strlen只接收指针(地址),错误

4.arr[1]是数组首元素,因为strlen只接收指针(地址),错误,随机值

5.&arr是整个数组的地址,在数值上等同于首元素地址,结果是6

6.&arr是整个数组的地址,+1就是像后移动一整个数组的距离(因为&arr这个指针的类型是

char(*)[7]  ),指向数组后一格的地址,不确定找不找得到\0,结果是随机值。

7.&arr[0],是取首元素的地址,+1就是向下一个元素移动(&arr[0]的类型是char*),因strlen的开始地址向后移动了一个字节,结果是5

字符指针(sizeof/strlen)

 const char *p = "abcdef";

p是指针,指针指向这个字符串“a b c d e f \0”。

p指向这个字符串,类型是char*,p指向的就是'a'所在的地址

1.printf("%d\n", sizeof(p));
2.printf("%d\n", sizeof(p+1));
3.printf("%d\n", sizeof(*p));
4.printf("%d\n", sizeof(p[0]));
5.printf("%d\n", sizeof(&p));
6.printf("%d\n", sizeof(&p+1));
7.printf("%d\n", sizeof(&p[0]+1));

1.p是指针,大小是4/8

2.p+1,因为指针p的类型是char*,所以+1是前进1字节,就是'b'的地址,大小是4/8

3.*p是对指针p解引用,p指向的是字符串,还是单个'a',可以看p的类型是什么,类型是char*,权限只够访问1个字节,所以p指向的是'a',*p就是字符'a',大小是1字节。

4.p[0]-->*(p+0),这里可以把p想象成数组,毕竟数组名也是指向首元素地址,所以这里是字符'a',大小是1字符

5.&p,是对指针p取地址,指针的地址也是指针,是二级指针,大小4/8

6.&p+1,也是二级指针,4/8

7.&p[0]+1中,&p[0]指向'a'的指针+1,变成了指向'b'的指针,还是指针,4/8

1.printf("%d\n", strlen(p));
2.printf("%d\n", strlen(p+1));
3.printf("%d\n", strlen(*p));
4.printf("%d\n", strlen(p[0]));
5.printf("%d\n", strlen(&p));
6.printf("%d\n", strlen(&p+1));
7.printf("%d\n", strlen(&p[0]+1));

1.p是指向 'a'的指针,算出字符串大小6

2.p+1就是'a'的地址再往后一位的地址,'b'的地址,结果算出字符串大小5

3.*p对p解引用,得到的是'a',作为地址传给strlen,无法计算,会非法访问

4.p[0]和上一个一个道理,得到的是'a',没法传给strlen

5.&p取p的地址,是二级指针,但这个地址对求字符串地址没用,得出的还是随机值

6.&p+1同理,随机值

7.&p[0]+1是'a'的地址+1后的地址,是'b'的地址,结果算出字符串大小5

二维数组(sizeof)

int a[3][4] = {0};

一个3行4列的二维数组,元素类型是int

a[i]单独出现时,可以看作是二维数组第i行的一维数组的数组名使用,即a[i]是第i行一维数组的首元素地址(数组名是数组首元素地址)

1.printf("%d\n",sizeof(a));
2.printf("%d\n",sizeof(a[0][0]));
3.printf("%d\n",sizeof(a[0]));
4.printf("%d\n",sizeof(a[0]+1));
5.printf("%d\n",sizeof(*(a[0]+1)));
6.printf("%d\n",sizeof(a+1));
7.printf("%d\n",sizeof(*(a+1)));
8.printf("%d\n",sizeof(&a[0]+1));
9.printf("%d\n",sizeof(*(&a[0]+1)));
10.printf("%d\n",sizeof(*a));
11.printf("%d\n",sizeof(a[3]));

1.单一个a在sizeof内,就是求数组a的大小,类型int大小4,元素数12,大小4*3*4=48

2.a[0][0]就是二维数组第一行第一列的元素,大小是4

3.a[0]单独在sizeof,可以把a[0]视为第一行的一维数组的数组名,所以求的是第一行的一维数组的数组大小,是4*4=16

4.a[0]是数组名,+1,则a[0]是第一行一维数组的首元素地址,类型是int*,+1就成了第一行一维数组的第2个元素地址。4/8

5.a[0]+1是第一行一维数组的首元素地址加一,就是第一行第2个元素,类型是int*,对这个地址解引用,大小是4

6.a+1,因为是二维数组,所以可以抽象一下,这个二维数组的前一组元素是行,每一个元素就是每一行一维数组,所以数组名a表示“数组首元素地址”就是第一行数组的地址。后一组元素就是在每一行一维数组下的每一个元素。所以这里先a是二维数组的地址,就是第一行数组的地址,+1就是第二行地址,类型是int(*)[4],(加1跳过4个元素),4/8

7.a+1是第二行数组的地址(不是第二行数组首元素地址,别搞混了),解引用得到第二行一维数组,大小是16

方便理解:

8.a[0]是第一行一维数组名,&数组名指取整个数组地址,&a[0]是取整个第一行一维数组地址,+1是整个第二行数组的地址,4/8。

9.对这个指针(整个第二行数组的地址)解引用,得到的是整个第二行数组,大小是16

10.单个a是指第一行的一维数组的地址,解引用就是第一行数组,大小是16

11.答案是16,虽然看起来a[3]是超出数组的,但是操作符sizeof是不会去运算括号里的内容的,专业点说就是不会访问这里面的空间的,判断大小是看类型判断。a[3]的类型是int(*)[4],所以大小任然和一行数组的大小是一样的。

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值