2023年最新c语言数组的指针c语言数组指针的用法实用.docx
2023年最新c语言数组的指针c语言数组指针的用法实用 在日常的学习、工作、生活中,确定对各类范文都很熟识吧。信任很多人会觉得范文很难写?以下是我为大家搜集的优质范文,仅供参考,一起来看看吧 c语言数组的指针 c语言数组指针的用法篇一 由于数据的表现形式多种多样,还有字符型和其它的数值类型,因此仅有基本数据类型是不够的。是否可以通过基本数据类型的组合抽象构造其它的数据类型呢?下面是我为大家带来的c语言数组与指针详解的学问,欢迎阅读。 我们知道,一个基本数据类型的变量只能存储一个数据,比如: int data = 0x64; 假如须要存储一组int型数据呢?比如,1、2、3,则至少须要3个变量data0、data1、data2。比如: int data0 = 1, data1 = 2, data2 =3; 由于数据的表现形式多种多样,还有字符型和其它的数值类型,因此仅有基本数据类型是不够的。是否可以通过基本数据类型的组合抽象构造其它的数据类型呢?答案是可以的,构造数据类型数组就是这样产生的。 从概念的视角来看,int型整数1、2和3都是相同的数据类型,data0、data1和data2三个变量的共性是data,其差异性是下标不一样。因此可以将data0、data1和data2抽象为一个名字,然后用下标区分这些变量的集合data0、data1和data2。假如有以下声明: intdata3; /解读为data是int数组(元素个数3) 那么data3就成了存放3个int型数据1、2、3的data0、data1和data2所组成的数组,即可分别对data0、data1和data2赋值: data0 = 1, data1 =2, data2 = 3; 当然,也可以根据以下方式声明一个数组并进行初始化: intdata3 = 1, 2, 3; 通常将data称为数组(变量)名,data0、data1和data2被称为变量。因而可以说,数组是将相同类型数据的若干变量按有序的形式组织起来,用一个名字命名,然后用下标区分这些变量的集合。 由于数组是建立在其它类型的基础上,因此c将数组看作构造类型,在声明数组时必需说明其元素的类型。比如,int类型的数组、float类型的数组或其它类型的数组。而其它类型也可以是数组类型,在这种状况下,创建的是数组类型的数组,简称数组的数组。 在这里,定义了一个名为data的数组类型变量,它是由存放3个int型数据1、2、3的变量data0、data1和data2组成的。通常又将数组的各个变量称为数组的元素,而数组的元素是根据依次编号的,这些元素的编号又称为数组元素的下标。 由于有了下标,因此数组元素在内存中的位置就被唯一确定下来了。下标总是从0起先的,最终一个元素的下标为元素的个数减1(即2),data0叫第1个元素,data1叫第2个元素,data2叫第3个元素,也就意味着全部的元素在内存中都是连续存储的。 直观上,数组是由下标(或称为索引)和值所组成的序对集合,对于每个有定义的下标都存在一个与其关联的值,在数学上称为映射。除了创建新数组外,大多数语言对数组只供应两种标准操作:一个操作是检索一个值,另一个操作是存储一个值。 函数create(data, size)创建一个新的具有适当大小的空数组,初始时数组的每一项都没有定义。retrieve操作接受一个数组data和一个下标index,假如下标合法,则该操作返回与下标关联的值,否则产生一个错误。store操作接受一个数组data、一个下标index和一个项item的集合,即项是value值的集合,有时也将值(value)称为项(item),返回在原来数组中增加新的序对后的数组。 明显,int系的任何常量表达式都可以作为数组元素的下标。比如: int array3+5; / 合法 int array'a' /表示int array97; 上述定义之所以合法,因为表示元素个数的常量表达式在编译时就具有确定的意义,与变量的定义一样明确地安排了固定大小的空间。 虽然运用符号常量增加了数组的敏捷性,但假如定义采纳了以下的形式: int n = 5; int arrayn; /非法 因为标准c认为数组元素的个数n不是常量,虽然编译器好像已经“看到”了n的值,但intarrayn要在运行时才能读取变量n的值,所以在编译期无法确定其空间大小。运用符号常量定义数组长度的正确形式如下: #define n 10 int arrayn; 即可依据实际的须要修改常量n的值。 由于数组元素下标的有效范围为0n-1,因此datan是不存在的,但c语言并不检查下标是否越界。假如访问了数组末端之后的元素,访问的就是与数组不相关的内存。它不是数组的一部分,运用它确定会出问题。c为何允许这种状况发生呢?这要归功于c信任程序员,因为不检查越界可以使运行速度更快,所以编译器没有必要检查全部的下标错误。因为在程序运行之前,数组的下标可能尚未确定,所以为了平安起见,编译器必需在运行时添加额外代码检查数组的每个下标值,但这样会降低程序的运行速度。c信任程序员能编写正确的代码,这样的程序运行速度更快。但并不是全部的程序员都能做到这一点,越界恰恰是初学者最简单犯的错误,因此要特殊留意下标的范围不能超出合理的界限。 当将变量data0、data1和data2作为的操作数时,data0是指向变量data0的指针,data1是指向变量data1的指针,data2是指向变量data2的指针。data0、data1和data2变量的类型为int,data0、data1和data2指针的类型为int *const,即指向常量的指针,简称常量指针,其指向的值不行修改。比如: int a; int * const ptr = a; ptr = null; /试图修改,则编译报警 a = null; /试图修改,则编译报警 同理,data是指向变量data的指针,那么data是什么类型? 根据声明变量的规约,将标识符data取出后,剩下的“int 3”就是data的类型,通常将其说明为由3个int组成的数组类型,简称数组类型。其目的是告知编译器须要安排多少内存?3个元素的整数数组,data类型测试程序详见程序清单 1.20。 程序清单 1.20 data类型测试程序 1 #include 2 3 void f(int x); 4 int main(int argc, char *argv) 5 6 int data3; 7 f(data); 8 return 0; 10 通过编译器提示的警告,“funtion: 'int' differ in levels ofindirection from 'int 3'”,说明数组变量data的类型为不是int而是int 3数组类型。由于在设计c语言时,过多地考虑了开发编译器的便利。虽然设计编译器更便利了,却因为概念的模糊给初学者造成了理解上的困难。事实上数组应当这样定义: int3 data; 即int是与3结合的。data究竟是什么类型? 当data作为的操作数时,则data是指向data的指针。由于data的类型为int 3,因此data是指向“int 3数组类型”变量data的指针,简称数组指针。其类型为int (*)3,即指向int 2的指针类型。为何要用“()”将“*”括起来? 假如不用括号将星号括起来,那么“int (*)3”就变成了“int *3”,而int*3类型名为指向int的指针的数组(元素个数3)类型,这是设计编译器时约定的语法规则。 data的类型究竟是不是“int (*)3”?其验证程序范例详见程序清单 1.21。 程序清单 1.21 data类型测试程序 1 #include 2 int main(int argc, char *argv) 3 4 int data3; 5 int b = data; 6 return 0; 7 通过编译器提示的警告,“'int' differ in levels ofindirection from 'int (*)3'”,说明data的类型为int (*)3。 (4)sizeof(data) 将如何找寻相应的数组元素呢?常用的方法是通过“数组的基地址+偏移量”算出数组元素的地址。在这里,第一个元素data0的地址称为基地址,其偏移量就是下标值和每个元素的大小sizeof(int)相乘。假设数组元素data0 的地址为a,且在内存中的实际地址为0x22ff74,那么data1的值为:当data作为sizeof的操作数时,其返回的是整个数组的长度。在这里,sizeof(data)的大小为12,即3个元素占用的.字节数为4×3=12,系统会认为data+1中的“1”,偏移了一个数组的大小,因此data +1是下一个未知的存储空间的地址(即越界)。在小端模式下,数组在内存中的存储方式详见图 1.10。 a + 1×sizeof(int) = (unsignedint)data + 4 = 0x22ff74 + 4 = 0x22ff78 data2的值为: a + 2×sizeof(int) = (unsigned int)data+ 8 = 0x22ff74 + 8 = 0x22ff7c 事实上,当在c语言中书写datai时,c将它翻译为一个指向int的指针。data是指向data0的指针,data+i是指向datai的,因此不管data数组是什么类型,总有data+i等于datai,于是*(data+i)等于datai,其相应的测试范例程序详见程序清单 1.22。 程序清单 1.22变量的地址测试程序 1 #include 2 int main(int argc, char *argv) 3 4 int data3= 1, 2, 3; 5 printf("%x, %x, %x, %x, %x",data0, data1, data2, data, data+1); 6 return0; 7 实践证明,虽然data0与data的类型不一样,但它们的值相等。同时也可以看出,数组的元素是连续存储的。假如将数组变量占用内存的大小除以数组变量中一个元素所占用空间的大小,便可得到数组元素的个数。即: int numdata = sizeof(data) / sizeof(data0); 当然,也可以运用宏定义计算数组元素的个数: #define nelems(data)(sizeof(data) / sizeof(data0) 当数组作为函数的参数时,c语言函数的全部参数必需在函数内部声明。但是,由于在函数内部并没有给数组安排新的存储空间,因此一维数组的容量只在主程序中定义。明显,假如函数须要得到一维数组的大小,则必需将它以函数参数的形式传入函数中,或将它作为全局变量访问。 标准c规定:除了“在声明中”或“当一个数组名是sizeof或的操作数”之外,只要数组名出现在表达式中,这编译器总是将数组名说明为指向该数组的第一个元素的指针。 虽然data在表达式中解读为指向该数组首元素data0的指针,但事实上data被解读为data0或等价于“*data=data0”,因此data与data0的值相等,且它们的类型都是int *const,即一个数组名是一个不行修改的常量指针(左值)。 依据指针运算规则,当将一个整型变量i和一个数组名相加时,其结果是指向数组第i个元素的指针,即data+index=dataindex,*(data+index)=dataindex,因此习惯性地将: int * ptr = data0; 写成下面这样的形式: int *ptr = data; 由于data的类型是不行修改的常量指针int*const,因此任何试图使数组名指向其它地方的行为都是错误的。比如: data +; /错误 虽然data有地址,但其类型为int *const,因此不能对data+赋值,同样也不能反过来给data赋值。比如: data = ptr; 类型地,象下面这样的表达式也是非法的: intdata3; data= 1, 2, 3; 但可以将data复制给指针变量ptr,通过变更指针变量达到目的。比如: #define n 10 int datan; int *ptr; for(ptr = data; ptr < data + n; ptr +) sum+= *ptr; for语句中的条件p int sum = 0; while(ptr < data +n) sum += *ptr+; 其中,*ptr+等价于*(ptr+),它的含义为自增前表达式的值是*ptr,即ptr当前指向的对象,以后再自增ptr。 s("content_relate");