【C语言】数组和指针

目录

 

一、&数组名VS数组名

二、数组指针

三、指针数组

四、函数指针

五、const和指针

1、常量指针

六、sizeof和指针、数组

七、strlen和字符数组

八、指针和数组笔试题

1、一维数组

2、字符数组 

3、二维数组


一、&数组名VS数组名

//试试这段代码
#include <stdio.h>int main(){int arr[10] = { 0 };printf("arr = %p\n", arr);printf("&arr= %p\n", &arr);}printf("arr+1 = %p\n", arr+1);printf("&arr+1= %p\n", &arr+1);return 0;

根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。

数组名表示数组首元素的地址,&数组名 表示的是数组的地址,而不是数组首元素的地址。

本例中&arr 的类型是: int(*)[10] ,是一种数组指针类型 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。

1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。

2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。

注意:数组名表示首元素的地址,二维数组的首元素是二维数组的第一行。

二、数组指针

数组指针是指向数组的指针。

int * p1[10];

int (*p2)[10];

//p1, p2分别是什么?

p1与[]结合,是指针数组,数组存放int类型的指针

p2与*结合,是数组指针,指针指向一个大小为10个整型的数组

这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

三、指针数组

 指针数组是存放指针的数组。

int*  arr1[10]; //整形指针的数组

char * arr2[4]; //一级字符指针的数组

char ** arr3[5];//二级字符指针的数组

数组指针和指针数组

int arr[5]; //数组

int *parr1[10]; //指针数组

int (*parr2)[10]; //数组指针

int (*parr3[10])[5];  //与[]结合所以是数组,数组有10个元素,数组元素的类型是int(*)[5]数组指针类型

四、函数指针

//看一段代码
#include <stdio.h>void test(){printf("hehe\n");}int main(){printf("%p\n", test);printf("%p\n", &test);return 0;}

输出的是两个地址,这两个地址是 test 函数的地址。 

//下面pfun1和pfun2哪个有能力存放test函数的地址?

void (*pfun1)();

void *pfun2(); 

存储地址,就要求pfun1或者pfun2是指针。 pfun1可以存放,pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。

五、const和指针

关键字const用来定义常量,如果一个变量被const修饰,那么它的值就不能再被改变。

1、常量指针

常量指针是指 针指向的内容是常量,可以有以下两种定义方式。

const int * p;

int const * p;

  • const在*左边,修饰的是*p,即p指向的值 ,所以不能通过这个指针改变变量的值。
  • 常量指针指向的值不能改变,但是这并不意味着指针本身不能改变,常量指针可以指向其他的地址。

2、指针常量 

指针常量是指 指针本身是个常量,不能再指向其他的地址,写法如下: 

 int *const p; 

  • const在*右边,修饰的是p,所以p这个指针的指向不能变。
  • 指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的。

六、sizeof和指针、数组

sizeof的作用是用来返回()里面的变量或者数据类型占用的内存字节数。

sizeof(数组名) 计算的是数组占用的存储大小;

sizeof(指针)在64位系统下是8字节,在32位系统下是4字节。

七、strlen和字符数组

size_t  strlen ( const char * str );

1、字符串已经'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包 含'\0')。

2、参数指向的字符串必须要以 '\0' 结束。

八、指针和数组笔试题

1、一维数组

//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

64位下运行结果:

 sizeof(a):sizeof数组名指整个数组的大小,所以是16个字节;

sizeof(a+0):a+0是首元素的地址,是指针类型,指针在64位下是8个字节;

sizeof(*a):*a是首元素,首元素的类型是int,所以是4个字节;

sizeof(a+1):a+1是第二个元素的地址,是指针类型,指针在64位下是8个字节;

sizeof(a[1]):a[1]是第二个元素,是int类型,4个字节;

sizeof(&a):&a表示数组的地址,是指针类型,指针在64位下是8个字节;

sizeof(*&a):*&a表示整个数组,大小是16字节;

sizeof(&a+1):&a+1依然是一个指针,在64位下是8个字节;

sizeof(&a[0]):&a[0]是首元素的地址,指针类型,在64位下是8个字节;

sizeof(&a[0]+1):&a[0]+1是第二个元素的地址,是指针类型,指针在64位下是8个字节。

2、字符数组 

//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

 64位:

注释掉的是因为编译报错。

strlen接收的是char*类型的参数。

因为数组里面没存\0,但strlen只有遇到\0才会结束,所以这只是个随机值。

 char arr[] = "abcdef";printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr+0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr+1));printf("%d\n", strlen(&arr[0]+1));

"abcdef"中隐藏一个\0,sizeof回把\0算进去,strlen只计算\0之前的个数,遇到\0才结束。

 char *p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p+1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p+1));printf("%d\n", sizeof(&p[0]+1));printf("%d\n", strlen(p));printf("%d\n", strlen(p+1));printf("%d\n", strlen(*p));printf("%d\n", strlen(p[0]));printf("%d\n", strlen(&p));printf("%d\n", strlen(&p+1));printf("%d\n", strlen(&p[0]+1));

3、二维数组

 //二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));

九、指针笔试题 

笔试题1

int main(){int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;}//程序的结果是什么?

 

a+1指向第二个元素,ptr指向5的下一个位置,ptr是int*类型,所以ptr-1指向5。

笔试题2

struct Test{int Num;char *pcName;short sDate;char cha[2];short sBa[4];}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main(){printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;}

32位:

第一个相当于是结构体指针+1跳过了一个结构体的大小,20个字节;

第二个就是无符号长整形,跳过一个字节;

第三个是指针,跳过4个字节。

笔试题3

 int main(){int a[4] = { 1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);printf( "%x,%x", ptr1[-1], *ptr2);return 0;}

ptr2:

因为是小端,所以是02 00 00 00

笔试题4

#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;}

 考察逗号运算符:最后一个逗号后面表达式的值作为整个表达式的值。

所以int a[3][2] = { (0, 1), (2, 3), (4, 5) };-->int a[3][2] = {1,3,5}

二维数组:

1 3

5 0

0 0

所以输出结果是1

笔试题5

 int main(){int a[5][5];int(*p)[5];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;}

 笔试题6

 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;}

 笔试题7

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

 笔试题8

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.mzph.cn/news/769762.shtml

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

相关文章

15:00面试,15:06就出来了,问的问题有点变态了

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到3月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降30%…

PTA L2-032 彩虹瓶

彩虹瓶的制作过程&#xff08;并不&#xff09;是这样的&#xff1a;先把一大批空瓶铺放在装填场地上&#xff0c;然后按照一定的顺序将每种颜色的小球均匀撒到这批瓶子里。 假设彩虹瓶里要按顺序装 N 种颜色的小球&#xff08;不妨将顺序就编号为 1 到 N&#xff09;。现在工…

基于cnn卷积神经网络的yolov8动物姿态估计识别(训练代码)

往期热门项目大合集&#xff1a; 人体姿态识别&#xff08;教程代码&#xff09;-CSDN博客 3D人体姿态估计&#xff08;教程代码&#xff09;-CSDN博客 3D目标检测&#xff08;教程代码&#xff09;_3d目标检测原理-CSDN博客 交通路标识别(教程&代码)_路标识别项目概述…

【c++】类和对象(二)this指针

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本节内容来到类和对象第二篇&#xff0c;本篇文章会带领大家了解this指针 目录 1.this指针1.1this指针的引出1.2this指针的特性1.3思考题1.4C语言和C实现Stack的对…

QB 系统配置模板

查询的时候&#xff0c;直接 在下面添加 一个字段就行&#xff01; public function getDeatil(){$post $this->request->post();if(!isset($post[id])){return out(请传递活动的id);}$builder new Builder($this->getModel());$builder->setFilter([id > …

轨迹预测后处理之非极大值抑制(NMS)

非极大值抑制是图像处理里面的一种算法&#xff08;比如边缘检测会使用到&#xff09; 轨迹预测这里借鉴了其思想&#xff0c;比如说对于某个场景中的某辆车&#xff0c;我们使用模型预测 64 条轨迹或者更多&#xff0c;以很好地捕获多模态性&#xff0c;同时每条轨迹对应一个…

看似简单的SQL,实则就是简单

加班遇到一个SQL问题&#xff0c;本想把别人的SQL改下成SparkSQL&#xff0c;在YARN上运行&#xff0c;然而数据一直对不上。 原SQL ⚠️说明&#xff1a;a.id&#xff0c;b.id没有空的&#xff0c;数据1:1&#xff0c;b.name可能存在空的 select a.id,b.id,b.name from tab…

MySQL数据库的备份

文章目录 MySQL数据库的备份MySQL备份方法完全备份物理备份备份 逻辑热备完全备份逻辑热备恢复恢复库恢复表 增量备份备份增量备份恢复基于位置进行恢复基于时间 MySQL数据库的备份 MySQL备份方法 物理备份&#xff1a; 物理备份涉及直接复制MySQL的数据文件和日志文件。这种…

FANUC机器人某个轴编码器损坏时进行单轴零点标定的具体方法

FANUC机器人某个轴编码器损坏时进行单轴零点标定的具体方法 前提: FANUC机器人编码器或其线路有损坏,一般先将机器人移动至零点位置,编码器相关部件更换完毕后,直接进行零点标定即可。但是对于突发的状况,这种方法显然是不行的,比如在生产过程中突然发生碰撞导致编码器相…

暴雨讲堂:AI时代第五代英特尔CPU能做什么?

如果把科技圈比作娱乐圈&#xff0c;那么这两年的顶流一定是AI。2023年&#xff0c;世人见证了ChatGPT在全球范围内的大火&#xff0c;以生成式AI为代表的新一轮人工智能应用问世&#xff0c;改变了人工智能&#xff08;AI&#xff09;技术与应用的发展轨迹&#xff0c;并开始在…

什么是进程

目录 一. 进程的概念二. 进程的组成三. 进程的特征四. 进程的状态与转换4.1 进程的状态4.2 进程状态的转换4.3 进程的组织方式 五. 进程控制5.1 进程控制5.2 进程创建 六. 进程之间的通信6.1 共享存储6.2 消息传递 \quad 一. 进程的概念 \quad 思考:操作系统是这些进程的管理者…

oracle19c单机版补丁19.3.0.0升级到19.22.0.0

oracle19c单机版补丁升级到19.22.0.0 一、获取补丁包 查看之前的版本 column product format A30 column version format A15 column version_full format A20 column status format A15 select * from product_component_version;二、备份opatch和数据库文件 su - oracle …

封装-练习

T2、以面向对象的思想&#xff0c;编写自定义类描述IT从业者。设定属性包括&#xff1a;姓名&#xff0c;年龄&#xff0c;技术方向&#xff0c;工作年限&#xff1b;方法包括&#xff1a;工作。 要求&#xff1a; 设置属性的私有访问权限&#xff0c;通过公有的get,set方法实现…

AD域的使用

一&#xff0c;部署共享网络驱动器 1/根目录下创建共享资料库-共享 2/用户-首选项-windows设置-网络驱动器-新建-映射驱动器 3/创建-共享路径-驱动器号(可固定/可随机) 4/更新策略:gpupdate /force 5/客户端查看 首先我们打开服务器此电脑 建立一个文件夹 右击文件夹点击属…

Avalonia(11.0.2)+.NET6 打包设置发布包的版本号

Avalonia11.0.2+.NET6 打包设置发布包的版本号 系统版本如何打包设置打包的版本号本文是对上一篇打包文章的补充,后台好多人私信我说打包的版本号如何设置,今天出个补充说明 Avalonia(11.0.2)+.NET6 打包运行到银河麒麟V10桌面系统 系统版本 如何打包 Avalonia(11.0.2)+.NET…

MVC与MVVM:两种前端架构模式对比

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

pytest教程-19-pytest.ini配置文件

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest内置fixture的使用方法&#xff0c;本小节我们讲解一下pytest.ini文件的配置方法。 pytest配置文件可以改变pytest的运行方式&#xff0c;它是一个固定的文件pytest.ini文件&#xff0c…

OpenGL学习笔记【4】——创建窗口,给窗口添加渲染颜色

一、前三章节的前情回顾 章节一&#xff1a;上下文(Context) OpenGL学习笔记【1】——简介-CSDN博客 章节一讲述了OpenGL在渲染的时候需要一个Context来记录了OpenGL渲染需要的所有信息和状态&#xff0c;可以把上下文理解成一个大的结构体&#xff0c;它里面记录了当前绘制使…

基于Java校园跑腿管理系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

自定义collate_fn函数:应对报错RuntimeError: stack expects each tensor to be equal size

使用BERT或ResNet分别生成文本和图像特征时,由于文本自身长度和图像大小的限制,导致最后形成的特征数据在送入DataLoader时会因为维度不同而报错: RuntimeError: stack expects each tensor to be equal size此时就需要自定义collate_fn函数实现数据的自定义加载功能,下面…