指针与数组间的“恩恩怨怨”

2024-04-20 17:48
文章标签 数组 指针 恩恩怨怨

本文主要是介绍指针与数组间的“恩恩怨怨”,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

指针与数组之间的"恩恩怨怨"

  • 前言
  • 1.数组(一维)
    • 1.1数组的内存布局
    • 1.2 a、&a、&a[0]的区别
  • 2.指针
    • 2.1指针的内存布局
    • 2.2 “*”好比门钥匙
    • 2.3 int * p = NULL 和 * p = NULL 有什么区别?
    • 2.4 p、&p、*p、p+1、*p+1、 *(p+1)、p[1]、&p[1]
  • 3.指针数组与数组指针--傻傻的分不清
    • 3.1指针数组与数组指针的内存布局

最近在学习语法的时候有了不小的收获,对数组和指针这两个玩意有了一些新的认识,也发现自己以前的理解存在很大的问题,谨以此文梳理吾之所得

前言

指针就是指针,指针变量在64位系统下始终占8个byte,指针可以指向任何地方,但不是任何地方都可以通过指针变量访问的

数组就是数组,是相同类型变量组成的集合(就是数学中集合的意思),数组的大小由组成变量的类型和元素的个数决定,满足等式:数组大小=元素类型大小*元素个数

这二位是八竿子打不着,完全没有任何关系

为什么要强调二者没有任何关系呢?

因为他们经常“穿着相同的衣服”逗你玩,不信看下面代码

void Usart_Printf(u8 *str){u8 data=0;do{// 		  USART_SendData(USART2,str[data]);//发送一个字USART2->DR = ( str[data]& (uint16_t)0x01FF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);//等待单字发送完成data++;}while(str[data]!=0);  //判断数据是否发送完成                                                  }

肯定会有人(以前的我)会认为str[data]为数组的一个元素,究竟是不是,看了下文你就明白了

1.数组(一维)

1.1数组的内存布局

int a[5];

定义了一个整形的数组a,其内存布局示意图如下:


在这里插入图片描述

首先编译器会根据定义数组的类型与元素个数划分出一块连续内存,再与a关联起来

a作为右值时 1,代表数组首元素的首地址而非数组的首地址,a不能作为左值

a[0]、a[1]…这些是a的元素,我们可以通过其访问这些元素的内容,但并不是说他们是这些元素的名字(了解即可,不求甚解)

1.2 a、&a、&a[0]的区别

这三者的区别,可能有朋友会傻傻的分不清,前面我们说了,a作为右值时代表数组首元素的首地址而非数组的首地址(不理解没关系,下面用实例证明),借用陈老师的《C语言深度解剖》里的话“省政府和市政的区别----&a[0]和&a 的区别”,&a表示整个数组的首地址如同四川的省政府在成都,&a[0]表示数组首元素的首地址如同成都的市政府也在成都,二者虽然在数值上是相等的,但物理意义完全不相同,而a与&a[0]则是等价的

实例证明:

#include "string.h"
#include "stdio.h"
int main()
{int a[5]={1,2,3,4,5};printf("%d %d %d\n",&a[0],a,&a);printf("%d %d %d",&a[0]+1,a+1,&a+1);return 0;}

运行截图:
在这里插入图片描述
&a[0],a,&a的值都为6422016(编译器分配的内存地址)看似没什么区别

但是:

&a[0]+1,a+1,&a+1的值分别为6422020、6422020、6422036,前两者的由6422016+sizeof(int)(首元素的首地址加上元素类型所占的空间)得来,可见二者没有任何区别,而&a+1则是由6422016+sizeof(int)*5(数组的首地址加上数组占的大小)得来

其实是通过物理意义来理解,“+1”就是在原有基础上移动一个单位,前二者表示元素的首地址其基础就是元素,后者表示的是数组的首地址其基础就是数组

相信看到这的朋友对数组已经有了相当的了解,接下来就来看看指针——“披着羊皮的狼”

2.指针

2.1指针的内存布局

int *p

定义指针p,其内存布局示意图如下:
在这里插入图片描述
如上图所示,我们把 p 称为指针变量,p 里存储的内存地址处的内存称为 p 所指向的内存,指针变量 p 里存储的任何数据都将被当作地址来处理,变量p本身的地址未知(根据编译器分配的不同而不确定)

*p前面的类型说明p所指向的内存存的数据类型

2.2 “*”好比门钥匙

如何理解 “ * ”?

我们已经知道指针变量p里面存的是且只能是地址,如果把这个地址比作是门牌号(某小区几单元几楼几号),那么 “ * ” 就好比是门钥匙,要知道门里有什么,那必须的要打开门吧,同理要知道地址对应的内存存了什么东西就必须要这把“钥匙” “ * ”

2.3 int * p = NULL 和 * p = NULL 有什么区别?

这是指针中比较经典的一个问题

首先说NULL在数值上和0是相等的,但和0的意义完全不同

在stdio.h中NULL的定义如下:

#if !defined(NULL) && defined(__NEEDS_NULL)
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

C++中被宏定义为0,C中被宏定义为空指针常量

int * p = NULL这句代码的意思是:定义一个指针变量 p,其指向的内存里面保存的是 int 类型的数据;在定义变量 p 的同时把 p 的值设置为0x00000000,而不是把*p 的值设置为 0x00000000

*p = NULL这句代码的意思是:给指针变量p所指向的内存赋值为0

2.4 p、&p、*p、p+1、*p+1、 *(p+1)、p[1]、&p[1]

  • p为指针变量,存储所指向内存的地址,类似于数组首地址a
  • ‘&’都不陌生,很明显这里是取地址符号,&p表示求取指针变量p本身的地址
  • *p带上了“钥匙”对吧,那它的功能必定就是获取“房间”里的东西,没错 *p就是获取所指向地址内存所存储的数据类似于数组a[0]
  • p+1表示在p的基础上移动一个“单位”,这里的“单位”就相当于数组中的下一个元素
  • *p+1表示在 *p的基础上加上1,这里的1理解为阿拉伯数字1,e.g. 如果 *p=1,那么 *p+1=2,注意这里并不是理解为“1+1=2”,而是1的ascll码‘0x31’+1=‘0x32’,‘0x32’对应就为字符2
  • *(p+1)很好理解,就是C语言运算符的优先级而已,不用说()的优先级当然高于 *
  • p[1]等价于*(p+1),这玩意就是“披着羊皮的狼”不注意还真会弄成是数组,这玩意完全可以当成数组元素那样理解,但和数组没有半毛钱关系,e.g. char *p=“Exclusive is handsome.”,p[0]=‘E’,p[1]=‘x’…
  • &p[1]就是取当前存储内容对应的地址

下面上代码帮助大家理解:

#include "string.h"
#include "stdio.h"
int main()
{int *p="ExclusiveTP is handsome.";printf("%d\n",sizeof(p));printf("%d %d %d %d\n",p,&p,p+1,&p[1]);printf("%c %c %c %c",*p,*(p+1),*p+1,p[1]);return 0;}

运行结果截图:
在这里插入图片描述
到这里我们现在可以明确分辨出前言部分中Usart_Printf(u8 *str)定义的是一个指针变量str,至于str[data]不过是“披着羊皮的狼”而已

3.指针数组与数组指针–傻傻的分不清

啥情况,指针数组?数组指针?不是说指针和数组没有半毛钱关系吗?^ - ^

是的,指针和数组没有半毛钱关系,但在某种情况下二者是可以结合的,就比如‘+’,‘-’都是算术运算符号,二者是独立存在的没有关系,但你总是会遇见加减混合运算吧,指针数组和数组指针就可以理解为混合体

3.1指针数组与数组指针的内存布局

指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决
定,它是“储存指针的数组” 的简称

数组指针:首先它是一个指针,它指向一个数组,在 64 位系统下永远是占 8 个字节,
至于它指向的数组占多少字节,不知道,它是“指向数组的指针” 的简称

二者定义如下:
int *p1[5];
int (*p2)[5];

哪一个是指针数组?哪一个是数组指针?

这里需要明白一个符号之间的优先级问题,“ [] ” 的优先级比 “ * ” 要高,p1 先与 “ [] ” 结合,构成一个数组的定义,数组名为 p1, int *修饰的是数组的内容,即数组的每个元素,那现在我们清楚,这是一个数组,其包含 5 个指向 int 类型数据的指针,即指针数组

至于 p2 就更好理解了,在这里 “ () ” 的优先级比 “ [] ” 高, “ * ” 号和 p2 构成一个指针的定义,指针变量名为 p2, int 修饰的是数组的内容,即数组的每个元素,数组在这里并没有名字,是个匿名数组,那现在我们清楚 p2 是一个指针,它指向一个包含 5个 int 类型数据的数组,即数组指针

下面附上二者的内存布局图帮助理解

在这里插入图片描述
老道只能“抛砖引玉”,因为我实则是搞硬件的,对数组和指针的要求并不是很高^ - ^

加油!拼命干才会百分百成功,下一篇再见!
  1. 右值为放在等号右边的值,左值即为等号左边的值 ↩︎

这篇关于指针与数组间的“恩恩怨怨”的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/920932

相关文章

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非