C语言--指针终章

 

目录

 

1. sizeof和strlen的对⽐

1.1 sizeof

1.2 strlen

1.3 sizeof 和 strlen的对⽐

 2. 数组和指针的理解——题目理解

2.1.sizeof

代码1:

代码2:

代码3:

代码4:

代码5(二维数组):

2.2:strlen

代码1:

代码2: 

代码3:

代码4(模拟实现strlen的三种方式):


冰冻三尺,非一日之寒

1. sizeof和strlen的对⽐

1.1 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.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:
size_t strlen ( const char * str );
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。
#include <stdio.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(arr2));return 0;
}

1.3 sizeof 和 strlen的对⽐

 2. 数组和指针的理解——题目理解

2.1.sizeof

代码1:

#include<stdio.h>
int main()
{int a[] = { 1,2,3,4 };//数组有几个元素printf("%zd\n", sizeof(a));//16 -- sizeof(数组名)的场景printf("%zd\n", sizeof(a + 0));//a是首元素的地址-类型是int*,a+0还是首元素的地址,是地址大小就是4/8printf("%zd\n",sizeof(*a));//a是首元素的地址,*a就是首元素,大小就是4个字节//*a == a[0] == *(a+0)printf("%zd\n",sizeof(a + 1));//a是首元素的地址,类型是int*,a+1跳过1个整型,a+1就是第二个元素的地址,4/8printf("%zd\n",sizeof(a[1]));//a[1]就是第二个元素,大小4个字节printf("%zd\n",sizeof(&a));//&a是数组的地址,数组的地址也是地址,是地址大小就是4/8个字节printf("%zd\n",sizeof(*&a));//1.*& 互相抵消了,sizeof(*&a)= sizeof(a)-16//2. &a 是数组的地址,类型是int(*)[4],对数组指针解引用访问的是数组,计算的是数组的大小 -16printf("%zd\n",sizeof(&a + 1));//&a+1是跳过整个数组后的那个位置的地址,是地址就是4/8个字节printf("%zd\n", sizeof(&a[0] + 1));//&a[0]+ 1 -- 数组第二个元素的地址,大小是4/8个字节printf("%zd\n",sizeof(&a[0]));//首元素的地址,大小4/8个字节return 0;
}

代码2:

#include<stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,计算的是数组的大小,单位是字节--6printf("%d\n", sizeof(arr + 0));//arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节//*arr --  arr[0] -- *(arr+0)等价printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小也是1个字节printf("%d\n", sizeof(&arr));//&arr是数组地址,数组的地址也是地址,大小是4/8//&arr -- char(*)[6]printf("%d\n", sizeof(&arr + 1));//&arr+1,跳过整个数组,指向了数组后边的空间,4/8个字节printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节return 0;
}

代码3:

include<stdio.h>
int main()
{char arr[] =  "abcdef" ;printf("%d\n", sizeof(arr));//arr是数组名,单独放在sizeof内部,计算的是数组中大小,是7个字节printf("%d\n", sizeof(arr + 0));//arr表示数组首元素的地址,srr+0还是首元素的地址,是地址就是4/8printf("%d\n", sizeof(&arr));//arr表示数组首元素的地址,*arr就是首元素。大小是1字节printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小是1个字节printf("%d\n", sizeof(&arr));//&arr是数组的地址,+1是跳过整个数组,还是地址,是地址就是4/8字节printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]+1是第二个元素的地址,大小是4/8个字节return 0;
}

代码4:

#include<stdio.h>
int main()
{const char* p = "abcdef";printf("%d\n", sizeof(p));//p是指针变量,我们计算的是指针变量的大小,4/8个字节printf("%d\n", sizeof(p + 1));//p+1是b的地址,是地址大小就是4/8个字节printf("%d\n", sizeof(*p));//p的类型是const char*,*p就是char类型了,1个字节printf("%d\n", sizeof(p[0]));//1.p[0] --> *(p+0) --> *p --> 'a',大小是1字节//2.把常量字符串想象成数组,p可以理解为数组名,p[0]就是首元素printf("%d\n", sizeof(&p));//取出的是p的地址,地址的大小就是4/8字节printf("%d\n", sizeof(&p + 1));//&p+1是跳过p指针变量后的地址,是地址就是4/8字节printf("%d\n", sizeof(&p[0] + 1));//4/8 &p[0]-取出字符串首字符的地址,+1是第二个字符的地址,大小是4/8字节return 0;
}

代码5(二维数组):

#include<stdio.h>
int main()
{int a[3][4] = { 0 };printf("%d\n", sizeof(a));//a是数组名,单独放在sizeof内部,计算的是数组打大小,单位是字节-48 =3*4*sizeof(int)printf("%d\n", sizeof(a[0][0]));//a[0][0] 是第一行第一个元素,大小4个字节printf("%d\n", sizeof(a[0]));//a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的中大小 16 个字节printf("%d\n", sizeof(a[0] + 1));//a[0]第一行的数组名,但是a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是//数组首元素的地址,就是&a[0][0],+1后是a[0][1]的地址,大小是4/8个字节printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示第一行第二个元素,大小就是4(int类型)printf("%d\n", sizeof(a + 1));//a作为数组名并没有单独放在sizeof内部,a表示数组数组首元素的地址,是二维数组首元素的地址,也就是//第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节printf("%d\n", sizeof(*(a + 1)));//1.a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小-16//2.*(a+1) == a[1],a[1]是第二行的数组名,sizeof(*(a+1))就相当于sizeof(a[1]),意思是把第二行的数组名单独放在//sizeof内部,计算的是第二行的大小printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的是数组的地址,就是第一行的地址//&a[0]+1 就是第二行的地址,是地址大小就是4/8个字节printf("%d\n", sizeof(*(&a[0] + 1)));//*(a[0] + 1)意思是对第二行的地址解引用,访问的就是第二行,大小就是16字节 printf("%d\n", sizeof(*a));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是//第一行的地址,*a就是第一行,计算的是第一行的大小,16字节//*a == *(a+0) ==a[0]printf("%d\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度//a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16字节return 0;
}

2.2:strlen

代码1:

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));//arr是首元素的地址,数组中没有\0,就会导致越界访问结果是随机的printf("%d\n", strlen(arr + 0));//arr+0是首元素的地址,数组中没有\0,就会导致越界访问是随机的printf("%d\n", strlen(*arr));//arr是首元素的地址,*arr是首元素,就是‘a’,‘a'的ascii码值是97//就相当于打97作为地址传递给了strlen,strlen得到的就是野指针,代码是有问题printf("%d\n", strlen(arr[1]));//arr[1]--'b'--98.传给strlen函数也是错误的printf("%d\n", strlen(&arr));//&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值 xprintf("%d\n", strlen(&arr + 1));//随机值x-6printf("%d\n", strlen(&arr[1] + 1));//第2个元素开始向后统计的,得到的也是随机值 x-1return 0;
}

代码2: 

#include<stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,计算的是数组的大小,单位是字节--6printf("%d\n", sizeof(arr + 0));//arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节//*arr --  arr[0] -- *(arr+0)等价printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小也是1个字节printf("%d\n", sizeof(&arr));//&arr是数组地址,数组的地址也是地址,大小是4/8//&arr -- char(*)[6]printf("%d\n", sizeof(&arr + 1));//&arr+1,跳过整个数组,指向了数组后边的空间,4/8个字节printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节return 0;
}

代码3:

#include<stdio.h>
#include<string.h>
int main()
{char* p = "abcdef";printf("%d\n", strlen(p));//6printf("%d\n", strlen(p + 1));//5pritnf("%d\n", strlen(*p));//*p就是‘a'-97,errprintf("%d\n", strlen(p[0]));//p[0]-->*(p+0)-->*p //errprintf("%d\n", strlen(&p));//&p是指针变量p的地址,和字符串“abcdef”关系不大//从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值printf("%d\n", strlen(&p + 1));//随机值printf("%d\n", strlen(&p[0] + 1));//5return 0;
}

代码4(模拟实现strlen的三种方式):

#include<stdio.h>
#include<string.h>
#include<assert.h>//计算器方式
int my_strlen1(char* str)
{int count = 0;assert(str);while (*str){count++;str++;}return count;
}//不创建临时变量记数器(递归)
int my_strlen2(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen2(str + 1);
}//指针-指针的方式
int my_strlen3(char* str)
{assert(str);char* p = str;while (*p != '\0')p++;return p - str;
}int main()
{char *a = "abcdef";int s = my_strlen1(a);printf("%d\n", s);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/595524.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分类预测 | Matlab实现DRN深度残差网络数据分类预测

分类预测 | Matlab实现DRN深度残差网络数据分类预测 目录 分类预测 | Matlab实现DRN深度残差网络数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现DRN深度残差网络数据分类预测&#xff08;完整源码和数据&#xff09;&#xff0c;运行环境为Matl…

【Docker系列】在 Linux 上安装 Docker Compose 的简明步骤

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

7.java openCV4.x 入门-Mat之转换、重塑与计算

专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1f4d6;我们唯一拥有的就是今天&#xff0c;唯一能把握的也是今天建议把本文当作笔记来看&#xff0c;据说专栏目录里面有相应视频&#x1f92b; &#x1f9ed;文…

单一职责原则

1.1 阅读干吗不直接用手机&#xff1f; 电子阅读器比较专注&#xff0c;而手机功能比较多&#xff0c;影响专注。 1.2 手机不纯粹 手机确实很方便。但是现在的手机就是一台小型智能电脑。它不仅能打电话&#xff0c;还能听音乐、看电影电视、与个人交流、与一群人群聊&#…

免费SSL证书申请指南

在互联网时代&#xff0c;HTTPS安全协议已成网站标配&#xff0c;而SSL/TLS证书是实现HTTPS的关键。以下是如何申请免费证书的简明流程&#xff1a; 1.选择证书颁发机构&#xff08;CA&#xff09;&#xff1a;现今很多知名CA如JoySSL、Lets Encrypt等提供免费SSL证书服务。选定…

LeetCode题练习与总结:插入区间--57

一、题目描述 示例 1&#xff1a; 输入&#xff1a;intervals [[1,3],[6,9]], newInterval [2,5] 输出&#xff1a;[[1,5],[6,9]]示例 2&#xff1a; 输入&#xff1a;intervals [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval [4,8] 输出&#xff1a;[[1,2],[3,10],[…

深度学习-机器视觉part2

深度学习-机器视觉part2 文章目录 深度学习-机器视觉part2一、从卷积到卷积神经网络二、手撕卷积代码2.1 动机2.2 数据集2.3 卷积操作2.3.1 填充&#xff08;padding&#xff09;2.3.2 卷积块2.3.3 池化2.3.4 Softmax 2.4 完整CNN2.5 训练改进 三、经典CNN模型介绍四、CNN模型的…

IDEA删除块注释(文档注释)/**

1. 问题缘由 在使用java写LeetCode的时候&#xff0c;有些题会有一些封装好的类&#xff0c;在本地编写代码的时候&#xff0c;如果没有定义好这些类&#xff0c;就会爆红&#xff0c;看着很难受&#xff0c;此时可以把官方定义好的类拿过来&#xff0c;但是这些类是有块注释的…

VM虚拟机部署code-server服务+tailscale内网穿透,实现随处coding

1.Linux下安装code-server Releases coder/code-server (github.com)https://github.com/coder/code-server/releases先去发布页面查看最新的code-server版本&#xff0c;下载命令示例&#xff1a; wget https://github.com/coder/code-server/releases/download/v4.22.1/co…

KeyguardClockSwitch的父类

KeyguardClockSwitch 定义在KeyguardStatusView中, mClockView findViewById(R.id.keyguard_clock_container);KeyguardClockSwitch的父类为&#xff1a; Class Name: LinearLayout Class Name: KeyguardStatusView Class Name: NotificationPanelView Class Name: Notificat…

如何注册midjourney账号

注册Midjourney账号比较简单&#xff0c;准备好上网工具&#xff0c;进入官网 Midjourney访问地址&#xff1a; https://www.midjourney.com/ 目前没有免费使用额度了&#xff0c;会员最低 10 美元/月&#xff0c;一般建议使用30美元/月的订阅方案。了解如何订阅可以查看订阅…

hive的使用(本地数据上传到idea)

1.首先第一步是先启动hive&#xff0c;hive的启动指令如下 nohup hiveserver2 & 2.然后我们进入idea中 这里我们使用的是idea里的Apache Hive的插件&#xff0c;进行配置&#xff0c;等我们跟moba连接好后&#xff0c;就可以进行数据的导入了。 hive的sql和mysql里的sql语…