指针的深入理解(六)
个人主页:大白的编程日记
感谢遇见,我们一起学习进步!
文章目录
- 指针的深入理解(六)
- 前言
- 一. sizeof和strlen
- 1.1sizeof
- 1.2strlen
- 1.3sizeof和strlen对比
- 二.数组名和指针加减
- 2.1数组名的理解
- 2.2指针加减整数
- 2.3指针的大小
- 三. 数组和指针笔试题解析
- 3.1 一维数组
- 3.2 字符数组
- 3.3常量字符串
- 四.二维数组
- 4.1二维数组的理解
- 4.2二维数组练习
- 后言
前言
经过前面的学习我们已经把指针的内容全部学完了。所谓”纸上得来终觉浅,绝知此事要躬行“。今天小编就带着大家进行指针知识的练习,也相当与复习一遍学过的内容。我们进入正题,向着大厂进发!
一. sizeof和strlen
1.1sizeof
- sizeof
在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的大小。
sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。
#inculde <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}
1.2strlen
- strlen
strlen 是C语言库函数,功能是求字符串长度。函数原型如下:
size_t strlen ( const char * str );
strlen函数是用来统计字符串个数的,统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为止,所以可能存在越界查找。
注意:strlen函数的使用需要包含头文件<string.h>
#include <stdio.h>
#include<string.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));printf("%d\n", sizeof(arr1));printf("%d\n", sizeof(arr1));return 0;
}
1.3sizeof和strlen对比
- 本质:sizeof是操作符 , strlen是库函数。
- 功能:sizeof计算空间大小,strlen统计字符个数。
- 注意事项:sizeof不关注内存内容,只关注内存大小
strlen通过观察内存的\0统计,遇到\0停下。若没有\0则可能产生越界现象。
二.数组名和指针加减
2.1数组名的理解
- 数组名是数组首元素的地址。
但有两个特殊情况: - sizeof(数组名),此时的数组名表示整个数组, 计算的是整个数组的大小,单位是字节。
&(数组名),此时的数组名也表示整个数组,取出的是整个数组的大小。
注意括号里必须只有数组名!
2.2指针加减整数
- 指针加减整数,指针向前或向后移动。
- 指针加减移动多大距离(单位是字节),取决于指针类型
- 举例:int类型的指针+1跳过一个整形,指向下一个整型。
指针地址+4
char类型的指针+1跳过一个字符,指向下一个字符。
指针地址+1
2.3指针的大小
- 指针大小取决于当前环境
- 32位环境指针大小4字节
- 64位环境指针大小8字节
三. 数组和指针笔试题解析
3.1 一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a+0));//2
printf("%d\n",sizeof(*a));//3
printf("%d\n",sizeof(a+1));//4
printf("%d\n",sizeof(a[1]));//5
printf("%d\n",sizeof(&a));//6
printf("%d\n",sizeof(*&a));//7
printf("%d\n",sizeof(&a+1));//8
printf("%d\n",sizeof(&a[0]));//9
printf("%d\n",sizeof(&a[0]+1));//10
printf("%d\n",sizeof(a));//1
//数组名单独放在sizeof里面,
//计算整个数组的大小 4*4==16
printf("%d\n",sizeof(a+0));//2
//a没有单独放在sizeof里面,
//a就是首元素地址
//指针+0跳过0的整型元素,还是指向首元素,
//地址就是指针,指针的大小是4/8
printf("%d\n",sizeof(*a));//3
//a是数组首元素地址,*a就是首元素
//int类型,4字节大小
printf("%d\n",sizeof(a+1));//4
//a首元素地址,a+1跳过一个整型,指向第二个元素
//指针加减整数还是指针,大小4/8字节
printf("%d\n",sizeof(a[1]));//5
//a[1]就是数组第二个元素,大小为4字节
printf("%d\n",sizeof(&a));//6
//&a取出数组首元素地址,数组的地址也是指针
//计算指针的大小,4/8字节
printf("%d\n",sizeof(*&a));//7
//&a取出整个数组的地址,*(数组的地址)访问呢整个数组
//计算整个数组的大小,4*4==16
printf("%d\n",sizeof(&a+1));//8
//&a是整个数组的地址,类型是数组指针,+1跳过整个数组
//指向数组后第一个字节的地址,地址是指针
//大小4/8字节
printf("%d\n",sizeof(&a[0]));//9
//a[0]数组首元素,&a[0]取出数组首元素地址
//地址就是指针,4/8字节
printf("%d\n",sizeof(&a[0]+1));//10
//a[0]数组首元素,&a[0]取出数组首元素地址
//首元素地址+1跳过一个整型,指向第二个元素
//还是指针,4/8字节
- 验证:
- 64位环境:
- 32位环境:
3.2 字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
printf("%d\n", sizeof(arr));//1
//arr数组名单独放在sizeof内部,计算整个数组的大小,1*6=6字节
printf("%d\n", sizeof(arr+0));//2
//arr是数组名,就是数组首元素的地址,+0跳过0的字节,指向首元素
//还是指针,4/8字节
printf("%d\n", sizeof(*arr));//3
//arr是数组首元素的地址,*arr解引用访问数组首元素,1字节
printf("%d\n", sizeof(arr[1]));//4
//arr[1]是数组第二个元素,1字节
printf("%d\n", sizeof(&arr));//5
//arr是数组名,&arr取出整个数组的地址,数组的地址也是地址
//还是指针,4/8字节
printf("%d\n", sizeof(&arr+1));//6
//&arr是整个数组的地址,+1跳过整个数组,指向数组后面的位置
//还是指针,4/8个字节
printf("%d\n", sizeof(&arr[0]+1));//7
//&arr[0]取出数组首元素的地址,+1跳过一个字节,指向第二个字符
//还是指针,4/8字节
- 验证:
- 64位环境:
- 32位环境:
char arr[] = {'a','b','c','d','e','f'};数组没有\0
printf("%d\n", strlen(arr));//1
//arr是数组名,数组首元素地址开始统计
//没有\0,什么时候遇到\0不知道,是随机值
printf("%d\n", strlen(arr+0));//2
//arr是数组名,是数组首元素地址,
//arr+0跳过0个字节,指向第一个元素,也是和上面一样的随机值
printf("%d\n", strlen(*arr));//3
//arr是数组名,是数组名首元素地址,*arr-'a'-ascllm码值97
//相当于把97作为地址传给strlen,strlen接收野指针,代码是错误的
printf("%d\n", strlen(arr[1]));//4
//arr[1]-'b'-98,把98传给strlen,也是野指针,也是错误的
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
printf("%d\n", strlen(arr));//1
//arr是数组名,数组首元素地址开始统计
//没有\0,什么时候遇到\0不知道,是随机值
printf("%d\n", strlen(arr+0));//2
//arr是数组名,是数组首元素地址,
//arr+0跳过0个字节,指向第一个元素,也是和上面一样的随机值
printf("%d\n", strlen(*arr));//3
//arr是数组名,是数组名首元素地址,*arr-'a'-ascllm码值97
//相当于把97作为地址传给strlen,strlen接收野指针,代码是错误的
printf("%d\n", strlen(arr[1]));//4
//arr[1]-'b'-98,把98传给strlen,也是野指针,也是错误的
printf("%d\n", strlen(&arr));//p1表示
//&arr取出数组的地址,数组的地址也指向数组首元素,设为x随机值
printf("%d\n", strlen(&arr+1));//p2表示
//&arr取出数组的地址,&arr+1跳过数组,指向数组后的位置,x-6的随机值
printf("%d\n", strlen(&arr[0]+1));//p3表示
//&arr[0]是数组首元素地址,&arr[0]+1跳过一个字节,指向第二个元素
//x-1的随机值
- 验证:
3.3常量字符串
双引号里面的字符串就是常量字符串,常量字符串末尾自动补上\0.
char arr[] = "abcdef"//常量字符串,末尾自动补\0
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
printf("%d\n", strlen(arr));//1
//arr是数组名,就是数组首元素地址,统计6个字符。
printf("%d\n", strlen(arr+0));//2
//arr是数组名,就是数组首元素地址,+0跳过0个字节
//还是数组首元素地址,//统计6个字符
printf("%d\n", strlen(*arr));//3
//arr是数组名,就是数组首元素的地址,*arr就是首元素'a'
//'a'的ascll码值是97相当于把97作为地址传递给strlen,strlen得到野指针
//此时代码是有问题的
printf("%d\n", strlen(arr[1]));//4
//arr[1]就是数组第二个元素,相当于把'b'--98传给strlen,
//也是野指针,也有问题
printf("%d\n", strlen(&arr));//5
//arr是数组名,&arr是数组首元素的地址,数组首元素的地址也指向首元素
//统计的还是6个字符
printf("%d\n", strlen(&arr+1));//6
//arr是数组名,&arr是数组首元素的地址,数组首元素的地址也指向首元素
//&arr+1跳过一个数组,指向数组后面的位置,什么时候遇到\0不知道
//所以是随机值
printf("%d\n", strlen(&arr[0]+1));//7
//&arr[0]取出数组首元素的地址,+1跳过一个字节,指向第二个字符,
//从第二个字符统计,统计5个字符
四.二维数组
4.1二维数组的理解
我们可以把二维数组看一个以数组为元素的一维数组。每行数组都有一个数组名,例如二位数组第一行的数组的数组名就是a[0],
第一行的数组的数组名就是a[1],以此类推。
举个例子来验证可不可以这样理解:
例如我们访问第二行第三个元素:
我们会写成a[1][2]
a[1]就是第二行的数组名,数组名就是数组首元素的地址。
首元素地址再通过【2】就跳过2个元素,访问第三个元素,
就是第二行第三个元素。说明我们的理解是没问题的。
4.2二维数组练习
int a[3][4] = {0};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a[0][0]));//2
printf("%d\n",sizeof(a[0]));//3
printf("%d\n",sizeof(a[0]+1));//4
printf("%d\n",sizeof(*(a[0]+1)));//5
printf("%d\n",sizeof(a+1));//6
printf("%d\n",sizeof(*(a+1)));//7
printf("%d\n",sizeof(&a[0]+1));//8
printf("%d\n",sizeof(*(&a[0]+1)));//9
printf("%d\n",sizeof(*a));//10
printf("%d\n",sizeof(a[3]));//11
printf("%d\n",sizeof(a));//1
//数组名单独放在sizeof里,计算整个数组的大小,
//3*4*4=48
printf("%d\n",sizeof(a[0][0]));//2
//a[0][0]表示数组首元素,大小为4字节
printf("%d\n",sizeof(a[0]));//3
//第一行数组名单独放在sizeof里,计算的是第一行数组的大小
//4*4=16字节;
printf("%d\n",sizeof(a[0]+1));//4
//a[0]第一行数组的数组名,就是第一行首元素的地址,+1指向第一行第二个元素,
//还是指针,4/8个字节
printf("%d\n",sizeof(*(a[0]+1)));//5
//a[0]+1是第一行第二个元素的地址,*解引用访问第一行第二个元素,4字节
printf("%d\n",sizeof(a+1));//6
//a是二维数组的数组名,就是数组首元素的地址,就是第一行的地址
//+1跳过一行,指向第二行,还是指针,4/8字节
printf("%d\n",sizeof(*(a+1)));//7
//a+1是第二行的地址,*解引用访问第二行,计算第二行的大小
//4*4=16字节
printf("%d\n",sizeof(&a[0]+1));//8
//a[0]是第一行的数组名,&a[0]取出第一行数组的地址,
//&a[0]+1跳过一行,指向第二行,还是指针
//指针大小就是4/8
printf("%d\n",sizeof(*(&a[0]+1)));//9
//&a[0]+1第二行的地址,*解引用访问第二行的数组,计算第二行数组的大小
//4*4=16字节
printf("%d\n",sizeof(*a));//10
//a是二维数组的数组名,数组名就是数组首元素的地址,就是第一行的地址
//*解引用访问第一行,计算第一行的大小。4*4=16
printf("%d\n",sizeof(a[3]));//11
//a[3]看似越界,但是并未访问,sizeof根据类型推断。
//所以a[3]无需真实访问,根据类型推断为第四行的数组名
//数组名单独放在sizeof内部,计算第四行数组的大小,4*4=16
后言
这里就是今天跟大家分享的全部内容啦,今天的内容有点绕,但是大家直到抓紧指针加减和数组名理解这两个点,那就迎刃而解啦!今天就分享到这里,感谢小伙伴的耐心阅读。咱们下期见!拜拜~