数组与指针

一个不带下标的数组名就是一个指向此数组的指针,具体来说就是第一个数组元素的地址。当一个指针变量被初始化为数组名时,就说该指针变量指向了数组(首元素)。

char str[20],*pstr;

pstr=str 等价于 pstr=&str[0]; 指针被置为指向数组(第一个元素),或者说指针存储了数组第一个元素的地址。

访问数组第6个元素,可以通过不同的方式:str[5], pstr[5], *(str+5), *(pstr+5)。

值得注意的是,pstr 是一个可以变化的指针变量,因此 pstr++; ++pstr; pstr+=5 都是正确的,而str是一个常数。因为数组一经声明定义,数组的地址也就被固定了,故 str++; ++str; str+=5 都是错误的。

任何能由数组下标完成的操作也可由指针来完成。编译系统在处理str[i]时,实际上就是将数组元素下标引用 str[i] 转换为等效的指针偏移表达式 *(str+i),然后再进行取值运算的。

需要注意的是,虽然基于数组名脚标引用时按数组元素的size为单位执行偏移计算,但是针对数组名本身的计算释义时稍有不同。典型的如sizeof(str)=20,正如 sizeof(int)=sizeof(char[4])=4,sizeof(str) 是计算str这种类型的字节数。str 的类型是 char[20],等效于 sizeof(char[20])。

那么,&str 代表什么呢?&str+1 到底指向了哪里呢?

&str 取地址得到指针,这种指针指向的类型是 char[20]。因此,&str+1 将偏移 sizeof(str),即偏移一个 char[20] 数组的字节数,指向下一个数组(的首元素)。

二维数组稍有不同,相应的引用二维数组 a[i][j] 则等价于 (*(a+i))[j] 或 *(*(a+i)+j),通常式子 *(a+i)+j 是用来计算元素所在内存地址,并不是它的内容。

    int a[3][4]; //二维整型数组,从右往左看,把一维数组int[4]当做一种类型,则a表示3个(int[4]),即成了数组(int[4])的数组。二维数组的元素类型为int[4]。

    int *q[12]; //整形指针数组,可以指向12个整数a[0][0]~a[2][3]

    int (*p)[4]; //整型数组指针,指向 int[4] 类型

这里数组名a的含义为指向二维数组第一个元素(int[4]型)的指针,针对a的算术运算是以一维数组int[4]为单位“1”进行偏移。

p=a; 中p指向a[0],则 p+1 不是指向a[0][1],而是指向 a[1]。需要注意的是 sizeof(p)=4,sizeof(a)=48。

/*二维数组即数组指针测试例程*/

#include <stdio.h>

int main(int argc, char** argv)
{
    int i;
    int a[3][4] = {
        1,2,3,4,
        5,6,7,8,
        9,10,11,12
    };
    
    /*指向第一个二维数组*/
    int (*p)[4] = a;
    
    /*打印二维数组的第一个元素:1,5,9*/
    printf("a=%d, a+1=%d, a+2=%d.\n", *(int*)a, *(int*)(a+1), *(int*)(a+2));
    printf("p=%d, p+1=%d, p+2=%d.\n", *(char*)p, *(char*)(p+1), *(char*)(p+2));
    
    /*打印第一个二维数组a[0]={1,2,3,4}*/
    for (i=0; i<4; i++)
    {
        printf("p[%d]=%d.\n", i, *((int*)p+i));
    }
    
    return 0;
}

假设是这么一个数组: int  arr[20]; 则arr的内存示意图为:

和指针变量相比, 数组没有一个单独的内存空间而存放其内存地址。即指针变量p是一个独立的变量,只不过它的值指向另一段连续的内存空间;而数组arr,本身代表的就是一段连续空间。

如果拿房间来比喻。指针和数组都是存放地址。只不过,指针是你口袋里的那本通讯录上写着的地址,你可以随时改变它的内容,甚至擦除。而数组是你家门楣上钉着的地址,你家原来是“复兴路甲108号”,你绝对不能趁月黑天高,把它涂改为“唐宁街10号”。 

数组是“实”的地址,不能改变。当你和定义一个数组,则这个数组就得根据它在内存中的位置,得到一个地址,如上图中的“0x1A000000”。只要这个数组存在,那么它终生的地址就是这个值。 

指针是一个“虚”的地址,可以改变地址的值。当你定义一个指针变量,这个变量占用4/8个字节的内存,你可以往这4字节的内存写入任意一个值,该值被当解读成一个内存地址。比如,你可以写入上面的“0x1A000000”,此时,指针p指向第一个元素。也可以改为“0x1A000003”,此时,指针p指向第二个元素。

参考:

指针

A TUTORIAL ON POINTERS AND ARRAYS IN C

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值