指针的深入理解(六)

指针的深入理解(六)

个人主页:大白的编程日记
感谢遇见,我们一起学习进步!


前言

经过前面的学习我们已经把指针的内容全部学完了。所谓”纸上得来终觉浅,绝知此事要躬行“。今天小编就带着大家进行指针知识的练习,也相当与复习一遍学过的内容。我们进入正题,向着大厂进发!


一. sizeof和strlen

1.1sizeof

  1. 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

  1. 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字节

  1. 验证:
  2. 64位环境:
  3. 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

后言

这里就是今天跟大家分享的全部内容啦,今天的内容有点绕,但是大家直到抓紧指针加减和数组名理解这两个点,那就迎刃而解啦!今天就分享到这里,感谢小伙伴的耐心阅读。咱们下期见!拜拜~
在这里插入图片描述

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-04-09 00:24:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-09 00:24:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-09 00:24:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-09 00:24:02       18 阅读

热门阅读

  1. 外贸建站公司排名

    2024-04-09 00:24:02       14 阅读
  2. 前端开发教程

    2024-04-09 00:24:02       16 阅读
  3. SpringBoot实现增删改查

    2024-04-09 00:24:02       12 阅读
  4. 复试专业课问题

    2024-04-09 00:24:02       13 阅读
  5. css外边距合并和BFC

    2024-04-09 00:24:02       12 阅读
  6. Leetcode 8. 字符串转换整数 (atoi)

    2024-04-09 00:24:02       12 阅读
  7. 蓝桥杯嵌入式之模块驱动

    2024-04-09 00:24:02       14 阅读
  8. 线程同步的四项原则

    2024-04-09 00:24:02       11 阅读