C++笔记 指针与数组 指针数组与数组指针_c++ 指针数组-程序员宅基地

技术标签: c++  c语言  visualstudio  C++笔记  开发语言  

指针:C语言中某种数据类型的数据存储的内存地址,例如:指向各种整型的指针或者指向某个结构体的指针。

数组:若干个相同C语言数据类型的元素在连续内存中储存的一种形态。

数组在编译时就已经被确定下来,而指针直到运行时才能被真正的确定到底指向何方。所以数组的这些身份(内存)一旦确定下来就不能轻易的改变了,它们(内存)会伴随数组一生;

而指针则有很多的选择,在其一生他可以选择不同的生活方式,比如一个字符指针可以指向单个字符同时也可代表多个字符等。

指针和数组在C语言中使用频率是很高的,在极个别情况下,数组和指针是“通用的”,比如数组名表示这个数组第一个数据的指针。

如下代码

#include <stdio.h>
char array[4] = {1, 2, 3, 4};
int main(void)
{
    char * p;
    int i = 0;
    p = array;
    for (; i < 4; i++)
    {
        printf("*array = %d\n", *p++);
    }
    return (0);
}

这里我们将数组名array作为数组第一个数据的指针赋值给p。但是不能写成*array++。准确来说数组名可以作为右值,不能作为左值(左值和右值的概念这里不再展开讲解)。

数组名的值其实是一个指针常量,这样我想你就明白了数组名为什么不能做为左值了。如果想用指针p访问array的下面2的数据,以下写法是合法的

char data;
/*第一种写法*/
p = array;
data = p[2];
/*第二种写法*/
p = array;
data = *(p+2);
/*第三种写法*/
p = array + 2;
data = *p;
指针与二维数组

先说一下二维数组,二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例:

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };

从概念上理解,a 的分布像一个矩阵:

0   1   2   3 

4   5   6   7 

8   9  10  11

但是内存是连续的,没有这样的“矩阵内存”,所以二维数组a分布是连续的一块内存。

C语言允许把一个二维数组分解成多个一维数组来处理。对于数组 a,它可以分解成三个一维数组,即 a[0]、a[1]、a[2]。每一个一维数组又包含了 4 个元素,例如 a[0] 包含 a[0][0]、a[0][1]、a[0][2]、a[0][3]。

那么定义如下指针如何理解呢?

int (*p)[4];

括号中的*表明 p 是一个指针,它指向一个数组,数组的类型为int [4],这正是 a 所包含的每个一维数组的类型。

那么和下面定义有什么区别呢?

int *p[4];

这里就要先说明*和[]的优先级了,[]的优先级是高于*的,所以int *p[4];等同于int *(p[4]);。所以它是一个指针数组。

这里很绕,总接下

int (*p)[4];数组指针,它指向二维数组中每个一维数组的类型,它指向的是一个数组。

int *p[4];是指针数组,它是一个数组,数组中每个数是指向int型的指针。

指针数组与数组指针

对于指针数组,说的已经很明确了,不再详细讲解,下面说一下数组指针。

举例看一下

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a[3][4] = { { 0, 1, 2, 3 },{ 4, 5, 6, 7 },{ 8, 9, 10, 11 } };
	int(*p)[4];
	p = a;
	printf("%d,%d,%d,%d\n", sizeof(*(p)),sizeof(*(p + 1)),sizeof(*(p + 2)),sizeof(*(p + 3)));

	printf("%d\n", **p);//a[0][0]
	printf("%d\n", *(*(p + 1)));//a[1][0]

	system("pause");
	return 0;
}

 

对于数组指针p如下

那么printf("%d\n", sizeof(*(p + 1)));的结果就是16

如果想打印a[1][0]的值,代码如下

printf("%d\n", *(*(p + 1)));

如果想打印a[1][1]的值,代码如下

printf("%d\n", *(*(p + 1)+1));

这个自行体会,p是数组指针,它指向的是一个数组,所以对获取它指向的值,也就是*p,是指向一个数组还是一个值,指向a[0]。想要获取a[0][0],就需要写成**p。

对指针进行加法(减法)运算时,它前进(后退)的步长与它指向的数据类型有关,p 指向的数据*p,它的类型是int [4],那么p+1就前进 4×4 = 16 个字节,p-1就后退 16 个字节,这正好是数组 a 所包含的每个一维数组的长度。也就是说,p+1会使得指针指向二维数组的下一行,p-1会使得指针指向数组的上一行。

最后再次捋一下数组指针和指针数组,

int *p1[4];是指针数组

int (*p2)[4];是数组指针

“[]”的优先级比“*”要高。

对于指针数组,p1先和“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。那么它本质是一个数组,这个数组里有4个指向int类型数据的指针。

对于数组指针,“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那么它本质是一个指针,它指向一个包含4个int 类型数据的数组。

既然深入谈了指针数组和数组指针,就多聊一下。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	char a[5] = { 'A', 'B', 'C', 'D' };
	char(*p3)[5] = &a;
	char(*p4)[5] = a;

	system("pause");
	return 0;
}

上面代码是编译编译是报了错误的,报警如下

注意:不同的编译器编译结果可能不同。

p3 这个定义的“=”号两边的数据类型完全一致,而p4 这个定义的“=”号两边的数据类型就不一致了。左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。所以才有了上面的错误。

但由于&a 和a 的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。不过编译器仍然警告你别这么用。

再举一个栗子

int vector[10];
int matrix[3][10];
int *vp,*vm;
vp = vector;
vm = matrix;

上面的代码第5行是错误的,因为vm是指向整型的指针,但是matrix不是指向整型的指针,他是指向整型数组的指针。下面是正确的写法

int matrix[3][10];
int (*vm)[10];
vm = matrix;

数组指针的应用

上面说了那么多,可能大部分开发者用不到,数组指针在很多时候都是可以代替二维数组的,有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。

#include <stdio.h>
#include <stdlib.h>
char *Names[] =
{
	"Bill",
	"Sam",
	"Jim",
	"Paul",
	"Charles",
	0
};

int main()
{
	char **nm = Names;
	while (*nm != 0)
	printf("%s \n", *nm++);

	system("pause");
	return 0;
}

具体运行我就不讲解了,运行结果如下

注意数组中的最后一个元素被初始化为0,while循环以次来判断是否到了数组末尾。具有零值的指针常常被用做循环数组的终止符。

这种零值的指针称为为空指针(NULL)。采用空指针作为终止符,在增删元素时就不必改动遍历数组的代码,因为此时数组仍然以空指针作为结束。

骚操作

写到这里想到一个“骚操作”,先看下面代码是否正确。

p[-1]=0;

初看这句代码,觉得奇怪,甚至觉得它就是错误,日常C语言开发基本有见到小标是负数的,但是仔细想想没有哪一本书说过下标能为负数的。看下面代码​​​​​​​

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int data[4] = { 0, 1, 2, 3 };
	int *p;
	p = data + 2;
	printf("p[-1] is %d\n", p[-1]);
	printf("*(p-1) is %d\n", *(p - 1));
	system("pause");
	return 0;
}

运行结果如下

不仅可以编译通过,还能正确的输出结果为1这表明,C的下标引用和间接访问表达式是一样的。当然不鼓励这种骚操作,代码需要很强的可读性,而不是这样的骚操作,这里只是演示下标引用和简介表达式的关系。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40933653/article/details/124025958

智能推荐

leetcode 172. 阶乘后的零-程序员宅基地

文章浏览阅读63次。题目给定一个整数 n,返回 n! 结果尾数中零的数量。解题思路每个0都是由2 * 5得来的,相当于要求n!分解成质因子后2 * 5的数目,由于n中2的数目肯定是要大于5的数目,所以我们只需要求出n!中5的数目。C++代码class Solution {public: int trailingZeroes(int n) { ...

Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。_outputstream释放-程序员宅基地

文章浏览阅读992次,点赞27次,收藏15次。UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节。文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1。注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。UTF-8字符集:汉字占3个字节,英文、数字占1个字节。GBK字符集:汉字占2个字节,英文、数字占1个字节。GBK规定:汉字的第一个字节的第一位必须是1。_outputstream释放

jeecgboot重新登录_jeecg 登录自动退出-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏3次。解决jeecgboot每次登录进去都会弹出请重新登录问题,在utils文件下找到request.js文件注释这段代码即可_jeecg 登录自动退出

数据中心供配电系统负荷计算实例分析-程序员宅基地

文章浏览阅读3.4k次。我国目前普遍采用需要系数法和二项式系数法确定用电设备的负荷,其中需要系数法是国际上普遍采用的确定计算负荷的方法,最为简便;而二项式系数法在确定设备台数较少且各台设备容量差..._数据中心用电负荷统计变压器

HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板_网页设计成品百度网盘-程序员宅基地

文章浏览阅读7k次,点赞4次,收藏46次。HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业_网页设计成品百度网盘

【Jailhouse 文章】Look Mum, no VM Exits_jailhouse sr-iov-程序员宅基地

文章浏览阅读392次。jailhouse 文章翻译,Look Mum, no VM Exits!_jailhouse sr-iov

随便推点

chatgpt赋能python:Python怎么删除文件中的某一行_python 删除文件特定几行-程序员宅基地

文章浏览阅读751次。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。AI职场汇报智能办公文案写作效率提升教程 专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。_python 删除文件特定几行

Java过滤特殊字符的正则表达式_java正则表达式过滤特殊字符-程序员宅基地

文章浏览阅读2.1k次。【代码】Java过滤特殊字符的正则表达式。_java正则表达式过滤特殊字符

CSS中设置背景的7个属性及简写background注意点_background设置背景图片-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏17次。css中背景的设置至关重要,也是一个难点,因为属性众多,对应的属性值也比较多,这里详细的列举了背景相关的7个属性及对应的属性值,并附上演示代码,后期要用的话,可以随时查看,那我们坐稳开车了······1: background-color 设置背景颜色2:background-image来设置背景图片- 语法:background-image:url(相对路径);-可以同时为一个元素指定背景颜色和背景图片,这样背景颜色将会作为背景图片的底色,一般情况下设置背景..._background设置背景图片

Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏8次。Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程

PyCharm2021安装教程-程序员宅基地

文章浏览阅读10w+次,点赞653次,收藏3k次。Windows安装pycharm教程新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载安装PyCharm1、进入官网PyCharm的下载地址:http://www.jetbrains.com/pycharm/downl_pycharm2021

《跨境电商——速卖通搜索排名规则解析与SEO技术》一一1.1 初识速卖通的搜索引擎...-程序员宅基地

文章浏览阅读835次。本节书摘来自异步社区出版社《跨境电商——速卖通搜索排名规则解析与SEO技术》一书中的第1章,第1.1节,作者: 冯晓宁,更多章节内容可以访问云栖社区“异步社区”公众号查看。1.1 初识速卖通的搜索引擎1.1.1 初识速卖通搜索作为速卖通卖家都应该知道,速卖通经常被视为“国际版的淘宝”。那么请想一下,普通消费者在淘宝网上购买商品的时候,他的行为应该..._跨境电商 速卖通搜索排名规则解析与seo技术 pdf

推荐文章

热门文章

相关标签