深度理解指针(5)----指针完结

news2024/12/23 20:00:34

hello,各位小伙伴们我们现在已经对指针有了深刻的理解,指针来到了收尾环节!让我们来做几题例题来复习之前学习的内容吧!

最近爆火的黑神话悟空不知道小伙伴们体验了没有,小编对八戒还有蜘蛛精的凄惨爱情深深打动特意找了一张他们的动漫合影!

一、sizeof和strlen的对比

1、sizeof

sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。

例如:

#include<stdio.h>
int main ()
{
    int a = 10;
    printf("%d\n", sizeof(a));
    printf("%d\n",sizeof(int));
    return 0;
}

sizeof是一个操作数!

2、strlen

strlen是C语言库函数,是用来求字符串的长度的·。格式:

size_t strlen (const char*str);

strlen统计的是字符串中\0之前的个数。

#include<stdio.h>
int main ()
{
    char arr1[3] = {'a','b','c'};
    char arr2[]  = "abcdef";
    printf("%d\n",strlen(arr1));
    printf("%d\n",strlen(arr2));
    return 0;
}

在字符数组中不包含\0而在字符串数组中末尾包含\0,同时要注意strlen只能用来统计字符数组的元素个数,不能统计整型数组元素个数!

二、数组和指针笔试题解析​

1、一维数组​

#include<stdio.h>
int main ()
{
    int a[] = {1,2,3,4};
    printf("%d\n",sizeof(a));// 16  此时传递的是整个数组,所以大小为4*sizeof(int)
    printf("%d\n",sizeof(a+0));// 4或8   a没有单独的放在sizeof中,所以a是数组首元素地址!,地址的大小为4或8
    printf("%d\n",sizeof(*a));// 4 同样a没有单独的放在sizeof中,a是数组首元素地址,解引用后为数组首元素!
    printf("%d\n",sizeof(a+1));// 4或8 a是数组首元素地址,+1后为数组第2个元素的地址
    printf("%d\n",sizeof(a[1]));// 4  a[1]是数组的第二个元素,为int类型
    printf("%d\n",sizeof(&a));// 4或8 此时&a是数组的整个地址,仍然是指针变量!
    printf("%d\n",sizeof(*&a));// 16  取出整个数组的地址后在进行解引用操作,为整个数组的元素
    printf("%d\n",sizeof(&a+1))// 4 或者8  取出整个数组的地址后,+1会跳过整个数组,虽然越界,但sizeof不会真实访问
    printf("%d\n",sizeof(&a[0]));// 4 或者8 表示的是数组首元素的地址
    printf("%d\n",sizeof(&a[0]+1));// 4 或者8  +1后表示数组第二个元素的地址
    return 0; 
}

2、字符数组​

#include<stdio.h>
int main ()
{
    char arr[] = {'a','b','c','d','e','f'};
    printf("%d\n", sizeof(arr));//6 一共6个字符,每个字符的大小为一个字节
    printf("%d\n", sizeof(arr+0));// 4或者8 传递的是数组首元素地址
    printf("%d\n", sizeof(*arr));// 1 arr没有单独的放入sizeof中,即表示数组首元素地址,解引用后为数组首元素!类型为char
    printf("%d\n", sizeof(arr[1]));// 1 表示数组中第二个元素,类型为char
    printf("%d\n", sizeof(&arr));// 4或者8  &arr传递的是整个数组的地址
    printf("%d\n", sizeof(&arr+1));// 4或者8 &arr传递整个数组后进行+1,会跳过整个数组,会越界但不会进行访问
    printf("%d\n", sizeof(&arr[0]+1));//4或者8  表示的是第二个元素的地址
    return 0;
}
#include<stdio.h>
int main ()
{
    char arr[] = {'a','b','c','d','e','f'};
    printf("%d\n", strlen(arr));// 随机值 strlen统计的是字符中\0之前字符的个数,但在字符数组中不存在\0,随机值
    printf("%d\n", strlen(arr+0));// 随机值 arr表示的是数组首元素的地址,从该地址向后统计\0之前元素的个数
    printf("%d\n", strlen(*arr));// 报错!arr仍然表示的是数组首元素地址,解引用以后为数组首元素,strlen的传参为指针类型,与规定传递类型不同!
    printf("%d\n", strlen(arr[1]));//  报错!
    printf("%d\n", strlen(&arr));// 随机值  &arr表示的是整个数组的地址,但仍然是从数组的首元素开始!,向后统计\0之前元素的个数!
    printf("%d\n", strlen(&arr+1));// 随机值  &arr表示的是整个数组的地址+1后会跳过整个数组!,之后在向后统计\0之前的元素个数!,但后面的内存中\0的位置未知,会是随机值
    printf("%d\n", strlen(&arr[0]+1));// 随机值 数组首元素地址+1后变为第二个元素的地址,从此次位置开始进行统计\0之前的元素个数
    return 0;
}

#include<stdio.h>
int main ()
{
    char arr[] = "abcdef";
    printf("%d\n", sizeof(arr));// 7 arr传递的是整个数组,统计整个数组中元素个数,包含\0(易错)
    printf("%d\n", sizeof(arr+0));// 4或者8   数组首元素地址
    printf("%d\n", sizeof(*arr));// 1  arr为数组首元素地址,解引用后为数组首元素类型为char
    printf("%d\n", sizeof(arr[1]));//  1 为数组第二个元素地址
    printf("%d\n", sizeof(&arr));//  4或8 
    printf("%d\n", sizeof(&arr+1));//  4或8
    printf("%d\n", sizeof(&arr[0]+1));//4或8
    return 0;
}
#include<stdio.h>
int main ()
{
   char arr[] = "abcdef";
    printf("%d\n", strlen(arr));// 6 arr表示数组首元素的地址,从当前的位置开始统计\0之前的字符个数 
    printf("%d\n", strlen(arr+0));// 6 同理
    printf("%d\n", strlen(*arr));// 报错 arr表示数组首元素的地址,解引用后为数组首元素,传递给strlen的参数错误会报错
    printf("%d\n", strlen(arr[1]));//  报错
    printf("%d\n", strlen(&arr));// 6 &arr虽然表示的数组的地址,但仍然是从数组的起始位置开始统计
    printf("%d\n", strlen(&arr+1));// 随机值 &arr+1后会从数组的首元素地址跳过整个数组,但后面的\0的位置未知
    printf("%d\n", strlen(&arr[0]+1));// 5  数组首元素地址+1为数组第二个元素的地址
    return 0;

}
#include<stdio.h>
int main ()
{
    char *p = "abcdef";//p是指针变量, 是数组首元素地址
    printf("%d\n", sizeof(p));// 4或8  p是指针变量
    printf("%d\n", sizeof(p+1));//  4或8  p是数组首元素地址,+1后变为数组第二个元素的地址
    printf("%d\n", sizeof(*p));//*p表示的是数组首元素,类型为char
    printf("%d\n", sizeof(p[0]));// 可以翻译为*(p+0),为数组首元素,类型为char
    printf("%d\n", sizeof(&p));//  4或8  p为数组首元素地址,将此地址取出放入到二级指针变量中,仍为指针
    printf("%d\n", sizeof(&p+1));// 4或8 二级指针变量+1后会跳过一个char*类型变量的大小
    printf("%d\n", sizeof(&p[0]+1));// 4或8 p[0]为a,&p[0]后为a的地址+1后b为的地址
    return 0;
}
#include<stdio.h>
int main ()
{
    char *p = "abcdef";
    printf("%d\n", strlen(p));//6
    printf("%d\n", strlen(p+1));//5
    printf("%d\n", strlen(*p));//err
    printf("%d\n", strlen(p[0]));//err
    printf("%d\n", strlen(&p));//随机值
    printf("%d\n", strlen(&p+1));//随机值
    printf("%d\n", strlen(&p[0]+1));//5

    return 0;
}

小伙伴自己尝试进行分析。

3、二维数组​

#include<stdio.h>
int main ()
{
    int a[3][4] = {0};
    printf("%d\n",sizeof(a));//  48 代表着整个数组,3*4*sizeof(int)
    printf("%d\n",sizeof(a[0][0]));//  4  代表数组的第一个元素
    printf("%d\n",sizeof(a[0]));// 16 16  a[0]是第一行的数组名,现在单独放在sizeof内部,计算的是一行的大小
    printf("%d\n",sizeof(a[0]+1));// 4或者8   a[0]是第一行的数组名,没有单独放在sizeof中即为数组第一行首元素地址,+1后为数组第二行首元素地址
    printf("%d\n",sizeof(*(a[0]+1)));//  4  数组第二行首元素地址解引用后为数组第二行首元素类型为int
    printf("%d\n",sizeof(a+1));// 4或者8   数组第二行的地址
    printf("%d\n",sizeof(*(a+1)));//16    
    printf("%d\n",sizeof(&a[0]+1));//4或者8
    printf("%d\n",sizeof(*(&a[0]+1)));//
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a[3]));
    return 0;
}

4、指针运算

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

在做指针类型的题目的时候要注意画图!

画完图后答案一目了然:2   5
//在X86环境下​
//假设结构体的大小是20个字节​
//程序输出的结果是啥?​
#include<stdio.h>
struct Test
{

 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p = (struct Test*)0x100000;//将16进制数强制类型转化成struct Test*指针类型,并赋值给p
int main()
{
 printf("%p\n", p + 0x1);//加1后要加上20个字节!要将十进制位转化成16进制位,即为0x100014
 printf("%p\n", (unsigned long)p + 0x1);//此时将p强制类型转化成(unsigned long)类型,为十进制数+1后为0x100001
 printf("%p\n", (unsigned int*)p + 0x1);//p转化为(unsigned int *)类型,+1后会加上4个字节即为0x100004
 return 0;
}
#include <stdio.h>
int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
}

让我们一起来动手画一画!

 小伙伴们要注意啦!花括号里面是逗号表达式,只会保留最后一位数字。这里非常容易忽出错!

#include <stdio.h>
int main()
{
 int a[5][5];
 int(*p)[4];
 p = a;
 printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
 return 0;
}

画图:

画完图后逻辑关系一目了然!要注意的是指针减去指针为中间元素的个数,同时指针是从底地址到高地址。第一个占位符是%p要将-4转化成补码后在转化成16进制的数!

运行结果为FFFFFFFFFFFFFFFC,-4

如果你已经看到这里,证明你非常优秀呢!加油。

 

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

 

#include <stdio.h>
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\n", *pa);
 return 0;
}

 

值得注意的是在指针数组中,存储的只是首字母!
运行结果为at。
终于我们迎来了最后一题,各位小伙伴们加油!
#include <stdio.h>
int main()
{
 char *c[] = {"ENTER","NEW","POINT","FIRST"};
 char**cp[] = {c+3,c+2,c+1,c};
 char***cpp = cp;
 printf("%s\n", **++cpp);
 printf("%s\n", *--*++cpp+3);
 printf("%s\n", *cpp[-2]+3);
 printf("%s\n", cpp[-1][-1]+1);
 return 0;
}
这道笔试题还是非常有难度的,这里小编只给大家画了草图,具体分析细节供给大家取分析!
今天所有关于指针的内容就结束啦,但小伙伴们要好好复习呀!拜拜,我们下期再见。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot使用Mongo数据库实现文件的上传下载预览等服务接口

MongoDB GridFS 简介 MongoDB GridFS是一个用于存储和检索大型文件的规范&#xff0c;它允许在MongoDB数据库中存储超过16MB的文件&#xff0c;如图片、音频、视频等。GridFS通过将文件分割成多个小的chunk&#xff08;文件片段&#xff09;&#xff0c;每个chunk通常为255KB&…

记URL重定向漏洞骚技巧

0x1 前言 这几天跟着我那几个师傅们在学习URL重定向漏洞&#xff0c;学习了比较多的对于这个漏洞的骚技巧&#xff0c;以及在挖掘edusrc漏洞和企业src相关的URL重定向漏洞时的一些技巧和不错的思路。 最近在跟我那几个师傅们研究学习URL重定向漏洞&#xff0c;然后在一些厂商…

EHS综合管理解决方案落地:管理效率飞升70%!

所有制造企业都面临着一个问题&#xff1a;如何保证EHS制度高质、高效执行&#xff1f;——上海斯歌EHS综合管理解决方案应运而生。 前不久&#xff0c;上海斯歌EHS综合管理解决方案&#xff08;企业安环综合管理解决方案&#xff09;在某全球领先的汽配公司成功落地&#xff0…

安灯系统在汽车电子工厂应用案例汇总

在汽车电子工厂中&#xff0c;高效的生产管理和及时的问题解决至关重要。安灯系统作为精益制造执行中的核心工具也是 MES 制造执行系统的重要组成部分&#xff0c;为汽车电子工厂带来了显著的效益。安灯系统是一个面向制造业生产现场&#xff0c;快速联络生产、物料、维修、主管…

VSCode中TypeScript调试配置

一、背景 最近想用TypeScript编译项目&#xff0c;在创建完项目后&#xff0c;我发现VSCode只有在调试TypeScript的单个文件时生效&#xff0c;如果存在引用&#xff0c;再进行断点调试&#xff0c;则调试功能不生效了。 随后&#xff0c;我让Chatgpt 生成一个一套配置&#…

C语言基础(二十五)

栈排序不是最高效的方法&#xff0c;因为栈是一种后进先出&#xff08;LIFO, Last In First Out&#xff09;的数据结构&#xff0c;而排序要求根据元素的顺序&#xff08;如升序或降序&#xff09;重新排列。但是&#xff0c;可以利用栈的特性&#xff0c;结合其他排序算法的思…

group by 中一定要包含 select 中的 除聚合函数以外 的 所有字段

今天在项目过程中报错&#xff1a; ### SQL: SELECT UNIT_NAME,dc.CAPTION as area,ifnull(a.bgSum,0) AS bgSum,ifnull(concat(FORMAT(a.bgSum/k.m*100,1),%),0.0%) as bgRatio FROM inspection_station_info isi left join dic_content dc on dc.CODE_VALUE…

K 线图快速绘制教程:使用 KLineChart 展示 DolphinDB K 线

KLineChart 是一款开源、简单易用、适用场景丰富的 Web 前端金融图表&#xff0c;基于 html5 canvas 构建&#xff0c;零依赖压缩包仅 40K&#xff0c;非常轻量。它可以用于渲染金融 K 线图&#xff0c;同时支持多种数据源&#xff0c;提供了丰富的交互功能以及指标计算接口。由…

动物消消乐:Scratch消除类游戏作品

小虎鲸Scratch资源站-免费Scratch作品源码,素材,教程分享平台! 体验《动物消消乐》&#xff0c;开启欢乐消除之旅&#xff01; 在这个快节奏的时代&#xff0c;放松心情、享受乐趣显得尤为重要。小虎鲸Scratch资源站为您带来了全新的游戏体验——《动物消消乐》。这款游戏不仅…

【CTF Web】BUUCTF Upload-Labs-Linux Pass-01 Writeup(JS分析+代码审计+文件上传)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的&#xff0c;专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关&#xff0c;每一关都包含着不同上传方式。 注意 1.每一关没有固定的…

上班摸鱼的人怎么治理?只要5个步骤让员工服服帖帖,打造干净职场

在职场中&#xff0c;我们时常会遇到一些同事在上班时间“摸鱼”&#xff0c;比如浏览与工作无关的网站、玩游戏、聊天等。这些行为不仅影响了工作效率&#xff0c;还可能损害团队的整体氛围和企业的利益。那么&#xff0c;如何有效地治理这种“摸鱼”现象呢&#xff1f;今天&a…

鸿蒙ArkTS小案例-购物车

最近用鸿蒙的ArkTS做了一个购物车的小案例&#xff0c;在这里分享一下&#xff0c;该购物车已实现如下功能&#xff1a; 1. 购物车商品数量支持1个或者多个 2. 勾选1个或者多个商品后&#xff0c;底部可以动态计算出购买总数量和总价格 3. 同时&#xff0c;可以对购买商品的…

SpringBoot对接Midjourney Api

提示&#xff1a;SpringBoot对接Midjourney Api 文章目录 目录 文章目录 后端代码 导包 controller层 工具类层 前端代码 申请API 测试结果 后端代码 导包 <!--添加hutool的依赖--><dependency><groupId>cn.hutool</groupId><artifactId&g…

IoT客户端+联邦学习微调大模型

大型模型的训练涉及到微调&#xff0c;微调则面临着高质量数据的稀缺性。与基于集中式数据中心的解决方案相比&#xff0c;物联网-IoT中大型模型的更新面临着分布式客户端私有且异构数据的协调挑战。为了解决这一挑战&#xff0c;作者提出了KOALA来推动物联网中大模型的训练。由…

单线程Redis:Redis为什么这么快

1 Redis是不是单线程 Redis 使用后台线程执行耗时的 I/O 操作&#xff0c;以免阻塞主线程 bio_close_file&#xff1a;后台 I/O 线程之一&#xff0c;异步关闭文件 bio_aof_fsync&#xff1a;后台 I/O 线程之一&#xff0c;异步地将 AOF&#xff08;Append Only File&#xff…

C++系列-STL容器之vector

STL概念 vector基本概念vector与数组的区别vector容器的特点动态大小连续存储自动扩容尾部操作高效 vector动态扩展的含义vector常用的接口示意 vector的构造函数vector赋值操作重载赋值assign赋值 vector的容量和大小vector的插入和删除vector数据存取vector互换容器vector互换…

音视频入门基础:WAV专题(7)——FFmpeg源码中计算WAV音频文件每个packet的size值的实现

一、引言 从文章《音视频入门基础&#xff1a;WAV专题&#xff08;6&#xff09;——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道&#xff0c;通过FFprobe命令可以显示WAV音频文件每个packet&#xff08;也称为数据包或多媒体包&#xff09;的信息&#xff0…

VMware16安装包+详细安装教程

VMware Workstation Pro16.0安装 安装包下载&#xff1a; 通过百度网盘分享的文件&#xff1a;VMware16.0.rar 链接&#xff1a;https://pan.baidu.com/s/1ZSWns5kJYUmhpZFjuKXqrQ?pwdv7s2 提取码&#xff1a;v7s2右键解压之后的安装包【VMware-workstation-full-16.0.0-16…

FrameNet介绍——从同义词语义知识库到框架语义知识库

FrameNet 是一个为期三年的项目&#xff0c;获得了 NSF&#xff08;美国国家科学基金会&#xff09;的支持&#xff0c;专注于基于语料库的计算词典编纂。 项目特点 FrameNet承诺使用语料库证据&#xff08;corpus evidence&#xff09;来进行语义和句法的概括&#xff1b; 并…

网络基础-实现在Windows系统下的socket环境地址通信

实现客户端和服务端的数据交互 1.写所要实现功能的声明&#xff08;封装在tcpsocket.h文件&#xff09; #ifndef TCPSOCKET_H #define TCPSOCKET_H//在Windows下进行网络编程&#xff0c;需要引入Windows的socket库 #include <winsock2.h> //做一些预编译工作&#xff…