指针与数组是C语言中很重要的两个概念,它们之间有着密切的关系,利用这种关系,可以增强处理数组的灵活性,加快运行速度,本文着重讨论指针与数组之间的联系及在编程中的应用。
1.指针与数组的关系
当一个指针变量被初始化成数组名时,就说该指针变量指向了数组。如:
char str[20], *ptr;
ptr=str;
ptr被置为数组str的第一个元素的地址,因为数组名就是该数组的首地址,也是数组第一个元素的地址。此时可以认为指针ptr就是数组str(反之不成立),这样原来对数组的处理都可以用指针来实现。如对数组元素的访问,既可以用下标变量访问,也可以用指针访问。
2.指向数组元素的指针
若有如下定义:
int a[10], *pa;
pa=a;
则p=&a[0]是将数组第1个元素的地址赋给了指针变量p。
实际上,C语言中数组名就是数组的首地址,所以第一个元素的地址可以用两种方法获得:p=&a[0]或p=a。
这两种方法在形式上相像,其区别在于:pa是指针变量,a是数组名。值得注意的是:pa是一个可以变化的指针变量,而a是一个常数。因为数组一经被说明,数组的地址也就是固定的,因此a是不能变化的,不允许使用a++、++a或语句a+=10,而pa++、++pa、pa+=10则是正确的。由此可见,此时指针与数组融为一体。
3.指针与一维数组
理解指针与一维数组的关系,首先要了解在编译系统中,一维数组的存储组织形式和对数组元素的访问方法。
一维数组是一个线形表,它被存放在一片连续的内存单元中。C语言对数组的访问是通过数组名(数组的起始地址)加上相对于起始地址的相对量(由下标变量给出),得到要访问的数组元素的单元地址,然后再对计算出的单元地址的内容进行访问。通常把数据类型所占单元的字节个数称为扩大因子。
实际上编译系统将数组元素的形式a[i]转换成*(a+i),然后才进行运算。对于一般数组元素的形式:<数组名>[<下标表达式>],编译程序将其转换成:*(<数组名>+<下标表达式>),其中下标表达式为:下标表达式*扩大因子。整个式子计算结果是一个内存地址,最后的结果为:*<地址>=<地址所对应单元的地址的内容>。由此可见,C语言对数组的处理,实际上是转换成指针地址的运算。
数组与指针暗中结合在一起。因此,任何能由下标完成的操作,都可以用指针来实现,一个不带下标的数组名就是一个指向该数组的指针。
4.指针与多维数组
用指针变量可以指向一维数组,也可以指向多维数组。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。
例如,在一个三维数组中,引用元素c[i][j][k]的地址计算最终将换成:*(*(*(c+i)+j)+k)。了解了多维数组的存储形式和访问多维数组元素的内部转换公式后,再看当一个指针变量指向多维数组及其元素的情况。
1 指向数组元素的指针变量
若有如下说明:
int a[3][4];
int *p;
p=a;
p是指向整型变量的指针;p=a使p指向整型二维数组a的首地址。
*(*(p+1)+2)表示取a[1][2]的内容;*p表示取a[0][1]的内容,因为p是指向整型变量的指针;p++表示p的内容加1,即p中存放的地址增加一个整型量的字节数2,从而使p指向下一个整型量a[0][1]。
2 指向由j个整数组成的一维数组的指针变量
当指针变量p不是指向整型变量,而是指向一个包含j个元素的一维数组。如果p=a[0],则p++不是指向a[0][1],而是指向a[1]。这时p的增值以一维数组的长度为单位。
5.指针与字符数组
C语言中许多字符串操作都是由指向字符数组的指针及指针的运算来实现的。因为对于字符串来说,一般都是严格的顺序存取方式,使用指针可以打破这种存取方式,更为灵活地处理字符串。
另外由于字符串以′\0′作为结束符,而′\0′的ASCII码是0,它正好是C语言的逻辑假值,所以可以直接用它作为判断字符串结束的条件,而不需要用字符串的长度来判断。C语言中类似的字符串处理函数都是用指针来完成,使程序运行速度更快、效率更高,而且更易于理解。
首先,p是指针变量,存放数组a首地址。
p是变量当然就能运算,不过指针变量只能进行加减运算。
再次,p是指向int类型的指针,所以对p加减1,就是p指向的地址加减一个int类型的长度,32位系统里int长度为4个字节。
所以*(p 1)就等于a[1]。
望采纳!
int *p;
int a[5] = {0,1,2,3,4};
p = a;//这里的意思是不是把a[0]地址赋给p?
//这是对的
那这样的结果也就是a[i] = p[i] ,可为毛会等价于*(p + i)呢?
*(p+i) 当 i=1时 p 加的可不是1 而是4
是int 的大小 分配的地址肯定是连续的
和你这个问题一样
L->elem = (int *)malloc(LIST_SIZE * sizeof(int));
printf("%d ", *(L->elem + i)); // 做指针运算
printf("%d ", L->elem[i]); // 只要内存地址是连续的不是数组也可以使用下标来取值。
上面两个得到的结果是一样的
所以我认为
1. c语言的数组应该是语法糖,只是malloc简单的连续地址指针而已。
2. 下标运算也是语法糖,其实现原理应该是指针运算。 (所以下标可以使用在数组中,也可以使用在指针中)
3. 由于数组和下标是基于指针的语法糖实现,导致c语言的数组根本没能力去检查数组的边界。 ( 上面这些都是我个人的猜测啊。)
类型标识符 * 变量名eg:char * Pointer性质数组名是一个常量,不能进行自增等运算. eg: Data++; X 指针是一个变量,能进行自增等运算. eg: Pointer++; √引用数组利用下标引用数组中的数据eg: a = Data[5]; 指针利用取值运算符引用所指向的数据 eg: a = *Pointer;其它 联系:当我们将一个指针指向一个数组后,指针后数组就有许多相同的地方了.如果在程序中使用了 Pointer = Data;(将指针指向数组).此时对数组的引用就可以使用指针变量了.具体如下:Pointer[i]表示*(Pointer+i),即通过带下标的指针引用数组元素 Pointer+i,Data+i; 表示Data[i]的地址,指向数组第i个元素 *(Pointer+i) ,*(Data+i) 表示Pointer+i和Data+i所指向的内容,即Data[i]