-
2022-04-24 14:08:38
指针数组存取数组的代码实现
一、定义字符数组和字符指针数组
char str[32]={}; char str1[32]={}; char str2[32]={}; char *sensordata[32];
个人理解:字符数组即一级指针,指针数组是二级指针,指向字符数组的地址或者一级指针的地址;
二、打印指针数据的基地址和指针的指向
printf("--------------指针数组的基地址-------------\n"); printf("sensordata[0]的地址: %p\n",&sensordata[0]); printf("sensordata[1]的地址: %p\n",&sensordata[1]); printf("sensordata[2]的地址: %p\n",&sensordata[2]); printf("\n--------------指针数组的下标指向-------------\n"); printf("sensordata[0]的地址: %p\n",sensordata[0]); printf("sensordata[1]的地址: %p\n",sensordata[1]); printf("sensordata[2]的地址: %p\n",sensordata[2]);
打印结果:
--------------指针数组的基地址-------------
sensordata[0]的地址: 0x7ffcbe058c10
sensordata[1]的地址: 0x7ffcbe058c18
sensordata[2]的地址: 0x7ffcbe058c20--------------指针数组的下标指向-------------
sensordata[0]的地址: 0x7ffcbe058d10
sensordata[1]的地址: 0x3
sensordata[2]的地址: 0x7ffcbe058d00- 由此可知,指针数组的的基地址也是按顺序的,相隔下标相差0x08.
- 指针数组里面存储的指针指向不确定的,随机的,无法知道指针数组指向的空间大小;
三、指针数组的下标指向字符数组,并格式化字符数组的内容
//指针数组的下标指向到数组 sensordata[0]=str; sensordata[1]=str1; sensordata[2]=str2; //格式化数组的内容,sprintf是不安全的函数,会导致缓存区溢出 sprintf(str,"airH:%.2f ",76.83); sprintf(str1,"airT:%.2f ",26.50); sprintf(str2,"ill:%d ",356); printf("\n--------------打印数组的内容-------------\n"); printf("str0的数据: %s\n",str); printf("str1的数据: %s\n",str1); printf("str2的数据: %s\n",str2); printf("\n--------------打印指针数组下标指向的内容-------------\n"); printf("sensordata[0]的数据: %s\n",sensordata[0]); printf("sensordata[1]的数据: %s\n",sensordata[1]); printf("sensordata[2]的数据: %s\n",sensordata[2]);
运行效果:
--------------打印数组的内容-------------
str0的数据: airH:76.83
str1的数据: airT:26.50
str2的数据: ill:356--------------打印指针数组下标指向的内容-------------
sensordata[0]的数据: airH:76.83
sensordata[1]的数据: airT:26.50
sensordata[2]的数据: ill:356- 指针数组的下标指向字符数组中,确定指针数组的指针指向;
- 使用sprintf格式化字符数组的内容,格式化的数据不能超过字符数据的长度,否则会引起内存溢出;
- 因指针数组里面的下标指向了字符数组,所以可以通过下标直接获取数组的数据;
四、打印字符数组的基地址和指针数组的指针指向
printf("\n--------------数组的基地址-------------\n"); printf("str的地址: %p\n",str); printf("str1的地址: %p\n",str1); printf("str2的地址: %p\n",str2); printf("\n--------------指针数组的指向的地址-------------\n"); printf("sensordata[0]的地址: %p\n",sensordata[0]); printf("sensordata[1]的地址: %p\n",sensordata[1]); printf("sensordata[2]的地址: %p\n",sensordata[2]);
运行效果:
--------------数组的基地址-------------
str的地址: 0x7ffcbe058d10
str1的地址: 0x7ffcbe058d30
str2的地址: 0x7ffcbe058d50--------------指针数组的指向的地址-------------
sensordata[0]的地址: 0x7ffcbe058d10
sensordata[1]的地址: 0x7ffcbe058d30
sensordata[2]的地址: 0x7ffcbe058d50
可见,指针数组里面的指针指向和字符数组的基地址一样,从而实现指针数据对数组的储存和获取操作!五、完整测试代码和效果显示
//gcc 7.4.0 #include <stdio.h> #include <string.h> int main(void) { char str[32]={}; char str1[32]={}; char str2[32]={}; char *sensordata[32]; printf("--------------指针数组的基地址-------------\n"); printf("sensordata[0]的地址: %p\n",&sensordata[0]); printf("sensordata[1]的地址: %p\n",&sensordata[1]); printf("sensordata[2]的地址: %p\n",&sensordata[2]); printf("\n--------------指针数组的下标指向-------------\n"); printf("sensordata[0]的地址: %p\n",sensordata[0]); printf("sensordata[1]的地址: %p\n",sensordata[1]); printf("sensordata[2]的地址: %p\n",sensordata[2]); //指针数组的下标指向到数组 sensordata[0]=str; sensordata[1]=str1; sensordata[2]=str2; //格式化数组的内容,sprintf是不安全的函数,会导致缓存区溢出 sprintf(str,"airH:%.2f ",76.83); sprintf(str1,"airT:%.2f ",26.50); sprintf(str2,"ill:%d ",356); printf("\n--------------打印数组的内容-------------\n"); printf("str0的数据: %s\n",str); printf("str1的数据: %s\n",str1); printf("str2的数据: %s\n",str2); printf("\n--------------打印指针数组下标指向的内容-------------\n"); printf("sensordata[0]的数据: %s\n",sensordata[0]); printf("sensordata[1]的数据: %s\n",sensordata[1]); printf("sensordata[2]的数据: %s\n",sensordata[2]); printf("\n--------------数组的基地址-------------\n"); printf("str的地址: %p\n",str); printf("str1的地址: %p\n",str1); printf("str2的地址: %p\n",str2); printf("\n--------------指针数组的指向的地址-------------\n"); printf("sensordata[0]的地址: %p\n",sensordata[0]); printf("sensordata[1]的地址: %p\n",sensordata[1]); printf("sensordata[2]的地址: %p\n",sensordata[2]); printf("sensordata的数据: %s\n",sensordata); return 0; }
Compilation time: 0.44 sec, absolute running time: 0.15 sec, cpu time: 0 sec, memory peak: 5 Mb, absolute service time: 0,69 sec --------------指针数组的基地址------------- sensordata[0]的地址: 0x7ffcbe058c10 sensordata[1]的地址: 0x7ffcbe058c18 sensordata[2]的地址: 0x7ffcbe058c20 --------------指针数组的下标指向------------- sensordata[0]的地址: 0x7ffcbe058d10 sensordata[1]的地址: 0x3 sensordata[2]的地址: 0x7ffcbe058d00 --------------打印数组的内容------------- str0的数据: airH:76.83 str1的数据: airT:26.50 str2的数据: ill:356 --------------打印指针数组下标指向的内容------------- sensordata[0]的数据: airH:76.83 sensordata[1]的数据: airT:26.50 sensordata[2]的数据: ill:356 --------------数组的基地址------------- str的地址: 0x7ffcbe058d10 str1的地址: 0x7ffcbe058d30 str2的地址: 0x7ffcbe058d50 --------------指针数组的指向的地址------------- sensordata[0]的地址: 0x7ffcbe058d10 sensordata[1]的地址: 0x7ffcbe058d30 sensordata[2]的地址: 0x7ffcbe058d50 sensordata的数据: ���
同时推荐一个在线编译器可以直接在网页上面测试案例;
更多相关内容 -
数组指针与指针数组
2021-01-20 14:02:37数组指针与指针数组 数组指针: 什么是数组指针:能够指向数组的指针。 定义一个int (*p)[10],首先()的优先级高于[]所以p首先是一个指针,指向的是一个整形的一维数组,所以是数组指针。 数组指针是一个指针不是... -
C语言 指针与数组的详解及区别
2021-01-01 05:03:42通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量。 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针的数组; ——数组并非指针&&指针并非... -
数组指针和指针数组
2019-09-17 16:39:06首先,理解一下数组指针和指针数组这两个名词: “数组指针”和“指针数组”,只要在名词中间加上“的”字,就知道中心了—— 数组的指针:是一个指针,什么样的指针呢?指向数组的指针。 指针的数组:是一个数组...首先,理解一下数组指针和指针数组这两个名词:
“数组指针”和“指针数组”,只要在名词中间加上“的”字,就知道中心了——
数组的指针:是一个指针,什么样的指针呢?指向数组的指针。
指针的数组:是一个数组,什么样的数组呢?装着指针的数组。
然后,需要明确一个优先级顺序:()>[]>*,所以:
(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;
*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。
根据上面两个分析,可以看出,p是什么,则词组的中心词就是什么,即数组“指针”和指针“数组”。
int *p1[5]; int (*p2)[5];
首先,对于语句“int*p1[5]”,因为“[]”的优先级要比“*”要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组。
图1
其次,对于语句“int(*p2)[5]”,“()”的优先级比“[]”高,“*”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含 5 个 int 类型数据的数组,如图 2 所示。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组。
图2
由此可见,对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。
数组指针 (*p)[n]
数组指针:是指针——指向数组的指针。
看下面的例子进行理解
#include "stdafx.h" int main() { //一维数组 int a[5] = { 1, 2, 3, 4, 5 }; //步长为5的数组指针,即数组里有5个元素 int (*p)[5]; //把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身 p = &a; //%p输出地址, %d输出十进制 //\n回车 //在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。 printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址 printf("%p\n", p); //根据上面,p为数组a的地址,输出数组a的地址 printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组 printf("%p\n", &a[0]); //a[0]的地址 printf("%p\n", &a[1]); //a[1]的地址 printf("%p\n", p[0]); //数组首元素的地址 printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1 printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1 printf("%d\n", *p[1]); //为一个绝对值很大的负数,不表示a[1]...表示什么我还不知道 //将二维数组赋给指针 int b[3][4]; int(*pp)[4]; //定义一个数组指针,指向含4个元素的一维数组 pp = b; //将该二维数组的首地址赋给pp,也就是b[0]或&b[0],二维数组中pp=b和pp=&b[0]是等价的 pp++; //pp=pp+1,该语句执行过后pp的指向从行b[0][]变为了行b[1][],pp=&b[1] int k; scanf_s("%d", &k); return 0; }
根据上面二维数组可以得出,数组指针也称指向一维数组的指针,所以数组指针也称行指针。
指针数组 *p[n]
指针数组:是数组——装着指针的数组。
看下面的例子进行理解:
#include "stdafx.h" int main() { int a = 1; int b = 2; int *p[2]; p[0] = &a; p[1] = &b; printf("%p\n", p[0]); //a的地址 printf("%p\n", &a); //a的地址 printf("%p\n", p[1]); //b的地址 printf("%p\n", &b); //b的地址 printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值 printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值 //将二维数组赋给指针数组 int *pp[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值 int c[3][4]; for (int i = 0; i<3; i++) pp[i] = c[i]; int k; scanf_s("%d", &k); return 0; }
最后,从上文来看:
数组指针是一个指针变量,占有内存中一个指针的存储空间;
指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。
了解指针数组和数组指针二者之间的区别之后,继续来看下面的示例代码:
int arr[5]={1,2,3,4,5}; int (*p1)[5] = &arr; /*下面是错误的*/ int (*p2)[5] = arr;
不难看出,在上面的示例代码中,&arr 是指整个数组的首地址,而 arr 是指数组首元素的首地址,虽然所表示的意义不同,但二者之间的值却是相同的。那么问题出来了,既然值是相同的,为什么语句“int(*p1)[5]=&arr”是正确的,而语句“int(*p2)[5]=arr”却在有些编译器下运行时会提示错误信息呢(如在 Microsoft Visual Studio 2010 中提示的错误信息为“a value of type"int*"cannot be used to initialize an entity of type"int(*)[5]"”)?
其实原因很简单,在 C 语言中,赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。在这里,p1 和 p2 都是数组指针,指向的是整个数组。p1 这个定义的“=”号两边的数据类型完全一致,而 p2 这个定义的“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。 -
详解C++中的指针结构体数组以及指向结构体变量的指针
2020-09-03 08:45:02主要介绍了C++中的指针结构体数组以及指向结构体变量的指针的用法,是C++入门学习中的基础知识,需要的朋友可以参考下 -
C++指针数组、数组指针、数组名及二维数组技巧汇总
2020-09-04 06:04:17主要介绍了C++指针数组、数组指针、数组名及二维数组技巧汇总,对于深入理解C++数组与指针来说非常重要,需要的朋友可以参考下 -
深入解析C++中的指针数组与指向指针的指针
2021-01-20 05:32:04指针数组定义:如果一个 数组,其元素均为指针型数据,该数组为指针数组,也就是说,指针数组中的每一个元素相当于一个指针变量,它的值都是地址。 形式:一维指针数组的定义形式为:int【类型名】 *p【数组名】 [4]... -
指针数组为字符串排序:1、冒泡排序 2、快速排序
2020-07-11 10:35:02指针数组为字符串排序,char* str[] = { "beijing","guangdong","shanghai" };进行排序,内涵冒泡排序和快速排序,原理:更改指针指向 -
C++中用new创建二维数组和指针数组实例代码
2020-08-31 02:46:46主要介绍了C++中用new创建二维数组和指针数组实例代码,非常不错,具有参考借鉴价值,需要的朋友参考下 -
深入理解数组指针与指针数组的区别
2020-09-05 07:29:22本篇文章是对数组指针与指针数组的区别进行了详细的分析介绍,需要的朋友参考下 -
c语言利用指针求数组的最大值与最小值
2019-05-16 22:44:17c语言利用指针求数组的最大值与最小值,下载资源,数组可扩展。 -
C语言 使用指针遍历数组 - C语言零基础入门教程
2021-08-25 14:25:03使用指针遍历数组 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.使用数组下标遍历数组 数组中的每个元素都有一个序号,这个序号从 0 开始,称为下标 index,例如,a[0] ...目录
零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门
一.使用数组下标遍历数组
数组中的每个元素都有一个序号,这个序号从
0
开始,称为下标index
,例如,a[0]
表示第1
个元素,a[3]
表示第4
个元素。数组是一个整体,它的内存是连续的,内存示意图:1.计算数组元素个数
计算数组元素个数示例如下:
int arr[] = {1,2,3,4,5}; int len = sizeof(arr)/sizeof(arr[0]); //正确的计算方式 int len = sizeof(arr); //错误的结算方式
2.通过下标遍历数组
/************************************************************************/ //@Author:猿说编程 //@Blog(个人博客地址): www.codersrc.com //@File:C语言教程 - C语言 使用指针遍历数组 //@Time:2021/06/18 08:00 //@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累! /************************************************************************/ #include<stdlib.h> #include<stdio.h> void main() { int arr[5] = { 10,20,30,40,50 }; int len = sizeof(arr) / sizeof(arr[0]);//计算数组长度 for (int i = 0; i < len; i++) { printf("根据下标索引值循环:数组下标:%d 对应的元素地址是: %d 对应的元素的值是: %d\n", i,&arr[i],arr[i]); } system("pause"); } /* 输出: 根据下标索引值循环:数组下标:0 对应的元素地址是: 1278408520 对应的元素的值是: 10 根据下标索引值循环:数组下标:1 对应的元素地址是: 1278408524 对应的元素的值是: 20 根据下标索引值循环:数组下标:2 对应的元素地址是: 1278408528 对应的元素的值是: 30 根据下标索引值循环:数组下标:3 对应的元素地址是: 1278408532 对应的元素的值是: 40 根据下标索引值循环:数组下标:4 对应的元素地址是: 1278408536 对应的元素的值是: 50 请按任意键继续. . . */
二.使用数组首地址偏移遍历数组
数组是一个整体,它的内存是连续的,那么我们可以直接通过首地址(数组名默认就是首地址)偏移来达到数组遍历的效果,内存示意图:
int arr[] = {1,2,3,4,5}; int value0 = *(arr); //arr默认指向数组的首地址,获取数组第一个元素的值 int value1 = *(arr + 1); //数组首地址偏移 +1 ,获取数组第二个元素的值 int value2 = *(arr + 2); //数组首地址偏移 +2 ,获取数组第三个元素的值 int value3 = *(arr + 3); //数组首地址偏移 +3 ,获取数组第四个元素的值
当知道数组元素地址之后,可以直接通过
*
获取该地址对应的值,使用数组首地址偏移遍历数组,示例代码如下:/************************************************************************/ //@Author:猿说编程 //@Blog(个人博客地址): www.codersrc.com //@File:C语言教程 - C语言 使用指针遍历数组 //@Time:2021/06/18 08:00 //@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累! /************************************************************************/ #include<stdlib.h> #include<stdio.h> void main() { int arr[5] = { 10,20,30,40,50 }; int len = sizeof(arr) / sizeof(arr[0]);//计算数组长度 for (int i = 0; i < len; i++) { printf("根据下标索引值循环:数组下标:%d 对应的元素地址是: %d 对应的元素的值是: %d\n", i,arr+i,*(arr + i)); } system("pause"); } /* 输出: 根据下标索引值循环:数组下标:0 对应的元素地址是: 1619000120 对应的元素的值是: 10 根据下标索引值循环:数组下标:1 对应的元素地址是: 1619000124 对应的元素的值是: 20 根据下标索引值循环:数组下标:2 对应的元素地址是: 1619000128 对应的元素的值是: 30 根据下标索引值循环:数组下标:3 对应的元素地址是: 1619000132 对应的元素的值是: 40 根据下标索引值循环:数组下标:4 对应的元素地址是: 1619000136 对应的元素的值是: 50 请按任意键继续. . . */
三.使用指针遍历数组
使用指针遍历数组实际上也是通过地址偏移,和上面的数组首地址偏移遍历数组类似:
示例代码如下:
/************************************************************************/ //@Author:猿说编程 //@Blog(个人博客地址): www.codersrc.com //@File:C语言教程 - C语言 使用指针遍历数组 //@Time:2021/06/18 08:00 //@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累! /************************************************************************/ #include<stdlib.h> #include<stdio.h> void main() { int arr[5] = { 10,20,30,40,50 }; int* p = arr; //定义一个空指针 int len = sizeof(arr) / sizeof(arr[0]);//计算数组长度 //int value1 = *p++; // int value1 = arr[1]; //int value2 = *p++; // int value2 = arr[2]; //int value3 = *p++; // int value3 = arr[3]; //int value4 = *p++; // int value4 = arr[4]; for (int i = 0;i<len;i++) { printf("根据指针偏移循环:数组下标:%d 对应的元素地址是: %d 对应的元素的值是: %d\n", i, p, *p); p++; //地址偏移+1,等价偏移到下一个元素地址 } system("pause"); } /* 输出: 根据指针偏移循环:数组下标:0 对应的元素地址是: 663747608 对应的元素的值是: 10 根据指针偏移循环:数组下标:1 对应的元素地址是: 663747612 对应的元素的值是: 20 根据指针偏移循环:数组下标:2 对应的元素地址是: 663747616 对应的元素的值是: 30 根据指针偏移循环:数组下标:3 对应的元素地址是: 663747620 对应的元素的值是: 40 根据指针偏移循环:数组下标:4 对应的元素地址是: 663747624 对应的元素的值是: 50 请按任意键继续. . . */
四.猜你喜欢
- 安装 Visual Studio
- 安装 Visual Studio 插件 Visual Assist
- Visual Studio 2008 卸载
- Visual Studio 2003/2015 卸载
- C 语言格式控制符/占位符
- C 语言逻辑运算符
- C 语言三目运算符
- C 语言逗号表达式
- C 语言 sizeof 和 strlen 函数区别
- C 语言 strcpy 和 strcpy_s 函数区别
- C 语言 memcpy 和 memcpy_s 区别
- C 语言 数组定义和使用
- C 语言 数组遍历
- C 语言 数组排序 – 冒泡法排序
- C 语言 数组排序 – 选择法排序
- C 语言 数组排序 – 插入法排序
- C 语言 数组排序 – 快速法排序
- C 语言 数组下标越界
- C 语言 数组内存溢出
- C 语言 数组下标越界和内存溢出区别
- C 语言 二维数组定义和使用
- C 语言 二维数组行数和列数计算
- C 语言 指针声明和定义
- C 语言 指针 p++ / p–
- C 语言 p++/§++/_(p++)/_p++
- C 语言 使用指针遍历数组
未经允许不得转载:猿说编程 » C 语言 使用指针遍历数组
-
指针数组、数组指针——用指针访问数组方法总结
2019-01-14 09:51:112.2.2 指向每一行的指针(指针数组方式) 2.2.3 指向整个数组的指针(数组指针方式) 3 总结 1.数组元素的访问 数组中的各元素在内存中是连续分布的,要想访问数组中某一元素,那么就必须知道其地址。 在一....目录
1.数组元素的访问
数组中的各元素在内存中是连续分布的,要想访问数组中某一元素,那么就必须知道其地址。
在一维数组中,数组A的元素A[i]的地址&A[i]=A+L*i,其中A为数组的标识符(数组名),也可以用A来代表数组的首地址,L为数组A的数据类型,由此可见,对于一维数组,只需要知道数据类型大小和索引i,就可以知道A[i]的地址,从而就可以访问A[i]了,这也是为什么一维数组的定义可以不指定数组大小,也不会妨碍数组元素的访问。
二维数组,实际上也是一维数组,只不过这个一维数组的每个元素都是一个一维数组。因此,将二维数组的每一行看做一个元素,很容易可以知道二维数组中各元素在内存中是按行优先进行连续存储的,如定义数组A[3][4],那么它在内存中的存储情况如下:
由此也可得到二维数组中元素A[i][j]的地址为&A[i][j]=A+L*(C*i+j),其中A为二维数组A的标识符(数组名),也就是数组的首地址,L为数组元素的数据类型,C为二维数组的列数。由此可见,要知道二维数组中某一元素的地址,就必须知道数据类型大小以及二维数组的列数,这样最终才能实现对二维数组元素的访问,这也是为什么二维数组的定义必须指定列数。
2.通过指针访问数组
在理解访问数组的指针之前,我们不得不先理解另一个问题:如果定义一个数组A,按前面所说,A就是数组第一个元素的首地址,那么A+1是什么意思呢?我在第一次遇到这个问题的时候,第一反应是A既然表示的是地址,那么A+1自然就是地址+1了呀!然而事实并非如此,我们先来做个测试如图所示:
根据测试可知,a+1并非就是a数值上加1,a+2也并非是a数值上加上2,他们实际上两两之间加的是4,即是sizeof(int),而*a=a[0]=1,*(a+1)=a[1]=2.....由此可以知道,a+i实际上就是a的第i个元素的地址,这与前面&A[i]的地址计算是相匹配的。
而对于二维数组来说,道理其实是一样的,不过二维数组的元素A[0]表示第一行,A[1]表示第二行......因此,二维数组中A是数组的首地址,也就是第0行A[0]的行首地址,A+1就是第1行A[1]的行首地址,.....,A+i就是第i行A[i]的行首地址了....
2.1 通过指针访问一维数组
一维数组指针的定义方式如下:
int a[4]={1,2,3,4}; int *p=a;
这里定义了一个指针变量p,它指向一个整型变量,而a实际上也就是a的第一个元素a[0]的地址,因此p就指向了数组的第一个元素a[0]。 那么p+1等于什么呢?实际上,p+1在数值上也就等于a+1,因此,p+1其实就是a[1]的地址,p+i就是a[i]的地址,这样,就可以通过*(p+i)来访问a[i]的值了。如图所示:
由此可以得出,对于一维数组的数组指针p,数组名p实际上是指向数组第一个元素的指针,即p为int *类型,由于其指向int型数据,因此(p+i)就相当于在p的基础上偏移了i*sizeof(int)的地址大小,就等于数组第i个元素的地址(i=0,1,2....)。
2.2 通过指针访问二维数组
2.2.1 指向元素的指针
这种办法可以说是最直接的办法了,定义方式如下:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p=&a[0][0];
在这种定义方式下,对于数组元素的访问就需要一个个元素往后推,结合本文开头所说的,二维数组是按行优先存储的,第i行第j列元素实际上是整个二维数组中的第i*c+j个元素,其中c为二维数组的列数,相对于第一个元素,第i*c+j个元素的地址偏移量为4*(i*c+j),而由于p为int指针,p+x的地址偏移量为p+4*x,因此a[i][j]=*(p+i*c+j)。
2.2.2 指向每一行的指针(指针数组方式)
这种方式是定义指针来指向二维数组的某一行,定义方式如下:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p=a[0];
这里可能会有些迷惑了,为什么这里的指针变量p是指向的a[0]呢?而不能让p指向a呢?
实际上,前面说过,二维数组实际上是一维数组中每个元素都为一个一维数组,那么此时定义了a[3][4],a代表什么呢?一定要知道,不管数组a是几维的,它实际上都是一维的,a一定是数组第一个元素的地址,这里的第一个元素是指的将n维数组看做一维数组后的第一个元素。因此,在a[3][4]中,将a看做一维数组后它的每一个元素实际上是每一行,因此如果让指针变量p指向a,就相当于让p指向第0行,而这里的第0行并不是整形变量,因此不能让p指向a;
而如果让p指向a[0],实际上就相当于指向a[0]的第一个元素,也就是a[0][0]了,此时的a[0][0]是整形变量,因此让p指向a[0]是可以的,当然,也可以让p指向a[1]、a[2].....如果让p指向第i行,那么此时的p+j就相当于是一维数组中第j个元素的地址了,即p+j就指向了a[i][j]。
这样看来,对于有r行的二维数组,就需要定义r个指针指向每一行,这样其实就可以定义一个装有r个指针的数组,其中每一个指针分别指向二维数组的每一行,定义方式如下:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p[3]; for(int i=0;i<3;i++)p[i]=a[i];
在这种定义方式下,p[i]即指向数组的第i行,也就是a[i][0],知道了a[i][0]的地址,要想访问a[i][j],地址即是a[i][0]+4*j,这里由于p[i]是int型的指针变量,因此刚好就等于p[i]+j,即a[i][j]=*(p[i]+j)。这就是一种定义指向二维数组的指针的方式,这里的p是以指针作为元素的数组,也就是指针数组。
值得注意的是,这种方法必须知道二维数组的行数。
2.2.3 指向整个数组的指针(数组指针方式)
这种方式是定义指针来指向整个数组,定义方式如下:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int (*p)[4]=a;
那么这里的p是什么意思呢?如果看不懂(*p)[4],那就把*p用b去替换掉,就成了b[4],这里的b就很明显了,就是一个有4个元素的数组的首地址,那么这里的p的含义也就不难得出了:指向一个有四个元素的数组的首地址,尤其需要注意的是,这里p是指向首地址,并非就是首地址,*p才是首地址,也就是指向第一个元素,因此这里的p也就是指向指针的指针。在int (*p)[4]=a中,p就是指向了第一个含四个元素的数组的首地址,也就是p指向a的首地址也就是a[0],*p指向a[0]的首地址也就是a[0][0],要访问a[0][0],就就是*(*p)了;
既然p是指向一个有四个元素的数组首地址的指针,那么p+i呢?*p+i呢?要分析清楚这个问题,我们还是参考b[4],前面说过,这里的p是指向首地址的指针,因此p+i就对应了&b+i,因此p+i就指向了&b+i所在的位置;*p是b的首地址,指向b的第一个元素,*p+i就对应了b+i,因此*p+i就指向了b+i所在的位置。
对于p+i,我们来看看&b+i和&b之间偏移了多少:
可以看到,&b+1偏移了16个字节,&b+2偏移了32个字节,而16个字节刚好就是数组b的大小,因此&b+i实际上偏移的地址为i*sizeof(b)=i*c*sizeof(int)。也就是说p+i会跳过整个包含四个整型元素的数组指向下一个包含四个元素的数组,回到a[3][4]中,p指向的是a[0],那么p+1就指向a[1],p+i就指向a[i]了,因此,p+i偏移i个b数组大小的地址,也就是指向二维数组的第i行。
而对于*p+i,就比较简单了,可以看做*p=b,那么*p+i也就是b+i,即是第i个元素的地址,因此也可得出*p+i指向当前有四个元素的数组的第i个元素。
好了,那么我们要是想访问数组中的a[i][j]怎么办呢?前面说过,要访问数组中的元素,必须先得到其地址,对于a[i][j],它是a数组中第i行的子数组中的第j个元素,综合上面分析的,p+i即指向了数组a的第i行,*(p+i)就是该行的首地址,也就是指向了a[i][0],而对于a[i]这个一维数组的第j个元素当然就是a[i]+j,也就是*(p+i)+j了,因此,a[i][j]的地址就是*(p+i)+j,a[i][j]=*(*(p+i)+j)。
3 总结
综合以上分析,总结一下用指针访问数组元素的方法(以数组a为例):
一维数组a[ ]
二维数组a[R ][ C ]
定义方式
T *p=a;
T *p=&a[m][n];
T *p[R];
p[m]=a[m];
(m=0,1..R-1)
T (*p)[C]=a;
访问方式
a[i]=*(p+i)
a[i][j]=*(p+(i-m)*C+(j-n))
a[i][j]=*(p[i]+j);
a[i][j]=*(*(p+i)+j)
-
数组指针、指针数组以及二位数组的深入解析
2020-09-05 01:43:30下面来讲讲多维数组与指针的关系。与普通数组一样,使用多维数组时,实际上将其自动转换为指向该数组第一个元素的指针 -
指针操作数组的两种方法(总结)
2021-01-20 05:44:49可以将指针指向数组的任意元素,然后从那里开始访问,只要注意不越界就行了,这说明数组只是将元素连续堆叠,并不需要也没有其他的配置信息存放在数组元素之外的地方或者在头尾等等任何地方,都没有,他只是连续的... -
指针数组与数组指针详解
2021-09-20 22:23:361.什么是指针数组和数组指针? 指针数组:指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。数组... -
c语言指针数组-·详解数组指针与指针数组
2022-04-25 21:29:57⾸先我们需要了解什么是数组指针以及什么是指针数组,如下图: int *p[5]; int (*p)[5]; 数组指针的意思即为通过指针引⽤数组,p先和*结合,说明了p是⼀个指针变量,指向⼀个⼤⼩为5的数组。 所以,int(*p)[5即为⼀... -
C语言指针变量可以当做数组
2020-03-27 17:04:35对的话在什么情况下可以这么使用? 答:不可以,因为w这时还是野指针。只有这样 int *w,a[44]; w=a; 操作后才可以,操作w就与操作a一样了。而且,操作指针比直接操作数组名更方便,因为指针是变量,可以++、–,而... -
C语言指针数组和数组指针详解
2022-04-12 21:07:45C语言文章更新目录 C语言学习资源汇总,史上最全面总结,没有之一 C/C++学习资源(百度云盘链接) ...C语言数组——一维数组 C语言数组——二维数组 C语言数组——字符数组 C语言中常用的6个字符串处理函 -
数组指针和指针数组的区别
2012-12-29 12:40:37数组指针和指针数组的区别 -
数组指针和指针数组区别判断
2022-03-24 18:33:592.1指针数组的使用 3.数组指针 3.1数组指针的使用 结语: 前言 对于c语言的初学者来说,往往容易将数组指针和指针数组混淆,本文将对二者概念以及其用法进行详细解释。 1.&数组名 vs 数组名 &arr和... -
指针数组,数组指针,存放数组指针的数组,指向存放数组指针数组的指针,函数指针,函数指针数组,指向函数...
2017-05-08 17:58:12数组:一组数据的集合...当然数组中除了存储一般常见的数据类型外,也可以用来存放指针,此时的数组就叫指针数组。指针数组:指针数组的元素全为指针。它的声明方法是:数据类型 * 数组名[数组长度];例如int arr[5]; -
C语言—利用指针引用数组
2021-05-21 05:13:04好了废话不多说了,之前我们了解了什么是数组,如何引用,我们又了解了什么是指针,怎么使用指针,那二者是否可以一同使用那,答案是当然的了。那么我们需要知道数组元素的指针是什么?换句话说我们需要知道数组在... -
PHP中使用数组指针函数操作数组示例
2020-12-19 02:42:06数组的内部指针是数组内部的组织机制,指向一个数组中的某个元素。默认是指向数组中第一个元素通过移动或改变指针的位置,可以访问数组中的任意元素。...在下面的示例中,将使用这些数组指针函数控 -
C语言指针——指针与数组
2021-03-20 18:32:52种一棵树最好的时间是十年前,其次是现在。 指针与数组 一、指针的运算 指针可以进行三种运算: 1.指针加上整数: ...当两个指针相减时,结果是指针在内存上的距离,可以用数组元素的个数来度量,所以如果指 -
易语言数组转指针
2020-07-22 20:56:31易语言数组转指针源码,数组转指针,子程序1,子程序2,子程序3,数组_整数转指针,数组_指针转整数,数组_文本转指针,数组_指针转文本,数组_字节集转指针,数组_指针转字节集,内存_申请,内存_释放,内存_取长度,内存_写入,...