数组访问形式
‘壹’ 访问数组中的某个元素可以通过什么来完成
与使用下标相比,使用指针能使C编译程序更容易地产生优质的代码。假设你的程序中有这样一段代码:
/* X la some type */
X a[MAX];
X *p; /*pointer*/
X x; /*element*/
int i; /*index*/
为了历数组a中的所有元素,你可以采用这样一种循环方式(方式a)
/*version (a)*/
for (i = 0; i<MAX; ++i)
{
x=a[i];
/* do something with x * /
}
你也可以采用这样一种循环方式(方式b)
/*veraion(b)*/
for (p = a; p<&a[MAX]; ++p )
{
x=*p;
/* do aomething with x * /
}
这两种方式有什么区别呢?两种方式中的初始情况和递增运算是相同的,作为循环条件的比较表达式也是相同的(下文中将进一步讨论这一点)。区别在于“x=a[]”和“x=*p”,前者要确定a[i]的地址,因此需要将i和类型x的大小相乘后再与数组a中第一个元素的地址相加;
后者只需间接引用指针p。间接引用是快速的,而乘法运算却比较慢。
这是一种“微效率”现象,它可能对程序的总体效率有影响,也可能没有影响。对方式a来说,如果循环体中的操作是将数组中的元素相加,或者只是移动数组中的元素,那么每次循环中大部分时间就消耗在使用数组下标上;如果循环体中的操作是某种I/O操作,或者是函数调用,那么使用数组下标所消耗的时间是微不足道的。
在有些情况下,乘法运算的开销会降低。例如,当类型x的大小为1时,经过优化就可以将乘法运算省去(一个值乘以1仍然等于这个值);当类型x的大小是2的幂时(此时类型x通常是系统固有类型),乘法运算就可以被优化为左移位运算(就象一个十进制的数乘以10一样)。
在方式b中,每次循环都要计算&a[MAX],这需要多大代价呢?这和每次计算a[i]的代价相同吗?答案是不同,因为在循环过程中&a[MAX]是不变的。任何一种合格的编译程序都只会在循环开始时计算一次&a[MAX],而在以后的每次循环中重复使用这次计算所得的值。
在编译程序确认在循环过程中a和MAX都不变的前提下,方式b和以下代码的效果是相同的:
/* how the compiler implements version (b) */
X *temp = &a[MAX]; /* optimization */
for (p = a; p< temp; ++p )
{
x =*p;
/*do something with x * /
}
遍历数组元素还可以有另外两种方式,即以递减而不是递增的顺序遍历数组元素。对按顺序打印数组元素这样的任务来说,后两种方式没有什么优势,但是对数组元素相加这样的任务来说,后两种方式比前两种方式更好。通过下标并且以递减顺序遍历数组元素的方式(方式c)如下所示(人们通常认为将一个值和。比较的代价要比将一个值和一个非零值比较的代价小:
/* version (c) */
for (i = MAX - 1; i>=0; --i)
{
x=a[i];
/* do aomcthing with x * /
}
通过指针并以递减顺序遍历数组元素的方式(方式d)如下所示,其中作为循环条件的比较表达式显得很简洁:
/* version (d) */
for (p = &a[MAX - 1]; p>=a; --p )
{
x =*P;
/*do something with x * /
}
与方式d类似的代码是很常见的,但不是绝对正确的,因为循环结束的条件是p小于a,而这有时是不可能的(见9.3)。
通常人们会认为“任何合格的能优化代码的编译程序都会为这4种方式产生相同的代码”,但实际上许多编译程序都没能做到这一点。笔者曾编写过一个测试程序(其中类型x的大小不是2的幂,循环体中的操作是一些无关紧要的操作),并用4种差别很大的编译程序编译这个程序,结果发现方式b总是比方式a快得多,有时要快两倍,可见使用指针和使用下标的效果是有很大差别的(有一点是一致的,即4种编译程序都对&a[MAX]进行了前文提到过的优化)。
那么在遍历数组元素时,以递减顺序进行和以递增顺序进行有什么不同呢?对于其中的两种编译程序,方式c和方式d的速度基本上和方式a相同,而方式b明显是最快的(可能是因为其比较操作的代价较小,但是否可以认为以递减顺序进行要比以递增顺序进行慢一些呢?);对于其中的另外两种编译程序,方式c的速度和方式a基本相同(使用下标要慢一些),但方式d的速度比方式b要稍快一些。
总而言之,在编写一个可移植性好、效率高的程序时,为了遍历数组元素,使用指针比使用下标能使程序获得更快的速度;在使用指针时,应该采用方式b,尽管方式d一般也能工作,但编译程序为方式d产生的代码可能会慢一些。
需要补充的是,上述技巧只是一种细微的优化,因为通常都是循环体中的操作消耗了大部分运行时间,许多C程序员往往会舍本求末,忽视这种实际情况,希望你不要犯相同的错误。
‘贰’ 使用数组名访问数组元素和使用指针变量访问数组元素有和不同
指针是可以随意移动的,而数组名不行,比如说定义一个
int a[4]={11,22,33,44};int *p=a;要访问其中的第二个元素,用数组名只能
用*(a+1)的方式,a不能自加或自减,而指针p则可以p++后,访问*p,也可以
*(p+1)的方式。
‘叁’ 对数组元素的访问有几种形式简述其优缺点。
你可以单个元素的赋值例如 a[1]=10;
也可以所有元素一起初始化 a[10]={1,2,3,4,5,6,7,8,9,10};
也可以声明指针访问 *(a+1) 等价于 a[1] *(a+2)=a[2]; ......
暂时想到这些 - -
有什么不懂可以追问
‘肆’ 指针与数组是如何访问的——可以用extern int *p作为int p[N]的外部声明吗
[摘要]C语言中,很多情况下指针与数组的的使用方式十分类似,使用数组名为一个指针变量赋值也是完全合法的。这造成一个假象,即数组就是指针,对
于它们二者的区别是一个老生常谈的话题,本文仅从指针与数组访问内存的方式进行区分,其余不再赘述。另外还讨论了使用指针作为数组的外部声明时产生的问
题,以及extern int a[]与extern int a[N]的一点小区别。
1、数组与指针访问内存的方式数组访问:指针访问指针偏移访问:可见,
指针访问内存的方式更为灵活,但它会增加一次额外的内存读取
,即先将指针的值从内存中读出来,再用它作为地址去访问数据。
2、使用指针作为数组的外部声明
例如以下代码:[cpp]view plainfile2.cintp[100];……file1.cexternint*p;……p[0]=1;
根据指针访问内存的方式,编译器首先提取p的值,在VC 6.0编译环境下,此处提取的是0x0000 0000,然后加上偏移量18CH,将1写入,程序崩溃。修正方法:使声明与定义相匹配
,声明为extern int p[];
3、数组声明中要不要写明元素个数
声明并不分配内存,只是告诉编译器对象的名字和类型,所以一般不需写明数组大小,但对于多维数组要写明左边一维之外的其他维的长度——给编译器足够的信息去产生代码。
但是,如果在引用变量处需要使用sizeof来取得数组大小,则必须指明,因为编译时编译器会计算出sizeof的结果。经试验,此处sizeof的结果只与声明中指定的元素个数相关,与定义处无关。
在上例中,如果按以下方式声明:[cpp]view plainexternintp[];//1externintp[100];//2externintp[50];//3
三者中sizeof(p)的结果分别是
‘伍’ 数组遍历常见的方式有
数组遍历常见的方式有:
一、forEach方法
forEach是最简单、最常用的数组遍历方法,它提供一个回调函数,可用于处理数组的每一个元素,默认没有返回值。
二、map方法
map,从字面上理解,是映射,即数组元素的映射。它提供一个回调函数,参数依次为处于当前循环的元素、该元素下标、数组本身,三者均可选。默认返回一个数组,这个新数组的每一个元素都是原数组元素执行了回调函数之后的返回值。
map方法不改变原数组。
三、filter方法
filter,过滤,即对数组元素的一个条件筛选。它提供一个回调函数,参数依次为处于当前循环的元素、该元素下标、数组本身,三者均可选。默认返回一个数组,原数组的元素执行了回调函数之后返回值若为true,则会将这个元素放入返回的数组中。
filter方法不改变原数组。
四、some、every方法
some方法和every的用法非常类似,提供一个回调函数,参数依次为处于当前循环的元素、该元素下标、数组本身,三者均可选。
数组的每一个元素都会执行回调函数,当返回值全部为true时,every方法会返回true,只要有一个为false,every方法返回false。当有一个为true时,some方法返回true,当全部为false时,every方法返回false。
some、every方法不改变原数组。
五、rece方法
rece方法有两个参数,第一个参数是一个回调函数(必须),第二个参数是初始值(可选)。回调函数有四个参数,依次为本轮循环的累计值、当前循环的元素(必须),该元素的下标(可选),数组本身(可选)。
rece方法,会让数组的每一个元素都执行一次回调函数,并将上一次循环时回调函数的返回值作为下一次循环的初始值,最后将这个结果返回。
如果没有初始值,则rece会将数组的第一个元素作为循环开始的初始值,第二个元素开始执行回调函数。
最常用、最简单的场景,是数组元素的累加、累乘。
rece方法不改变原数组。
六、for of方法
es6新增了interator接口的概念,目的是对于所有数据结构提供一种统一的访问机制,这种访问机制就是for of。
即:所有有interator接口的数据,都能用for of遍历。常见的包括数组、类数组、Set、Map等都有interator接口。
(5)数组访问形式扩展阅读:
数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。
数组是用于储存多个相同类型数据的集合。
在C语言中, 数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。
‘陆’ 怎么访问数组中的数据
使用for循环语句+文件操作函数即可文件中数据读取并存到数组中。
1、C语言标准库提供了一系列文件操作函数。文件操作函数一般以f+单词的形式来命名(f是file的简写),其声明位于stdio.h头文件当中。例如:fopen、fclose函数用于文件打开与关闭;fscanf、fgets函数用于文件读取;fprintf、fputs函数用于文件写入;ftell、fseek函数用于文件操作位置的获取与设置。一般的C语言教程都有文件操作一章,可以找本教材进一步学习。
2、例程:
#include<stdio.h>
int i,a[100];
int main(){
FILE * fp1 = fopen("input.txt", "r");//打开输入文件
FILE * fp2 = fopen("output.txt", "w");//打开输出文件
if (fp1==NULL || fp2==NULL) {//若打开文件失败则退出
puts("不能打开文件!");
rturn 0;
}
for(i=0;fscanf(fp1,"%d",a+i)!=EOF;i++);//从输入文件连续读取整数到数组a
for(;i--;)fscanf(fp2,"%d ",a[i]);//把数组a逆序写入到输出文件当中
fclose(fp1);//关闭输入文件
fclose(fp2);//关闭输出文件,相当于保存
return 0;
}
‘柒’ 汇编数组中的访问形式有几种呢能否举例参考一下
一维数组ARRAY ARRAY[SI] 首址ARRAY+偏移量[SI]
二维数组ARRAY ARRAY[SI][BX] 首址ARRAY+横向偏移[SI]+纵向偏移[BX]
‘捌’ 如何访问数组中的元素
具体步骤如下:
1、用list来演示,安装好python与pycharm之后,打开pycharm,新建Test_List.py。
‘玖’ php 中对数组访问的几种方式
主要有两种方式,一是for循环遍历,二四foreach遍历;
for循环主要通过循环嵌套实现遍历,
foreach和遍历一维数组差不多啦,主要是输出有差别.
如果我的回答没能帮助您,请继续追问。
您也可以向我们团队发出请求,会有更专业的人来为您解答。