3.6.指针与数组的天生姻缘

3.6.指针与数组的天生姻缘

3.6.1、以指针方式来访问数组元素

(1) 数组元素使用时不能整体访问,只能单个访问。访问方式有2种:数组形式和指针形式。
(2) 数组格式访问数组元素是:数组名[下标]; (注意下标从0开始)
(3) 指针格式访问数组元素是:*(指针+偏移量); 如果指针是数组首元素地址(a或者&a[0]),那么偏移量就是下标;指针也可以不是首元素地址而是其他哪个元素的地址,这时候偏移量就要考虑叠加了。
(4) 数组下标方式和指针方式均可以访问数组元素,两者的实质其实是一样的。在编译器内部都是用指针方式来访问数组元素的,数组下标方式只是编译器提供给编程者一种壳(语法糖)而已。所以用指针方式来访问数组才是本质的做法。

3.6.2、从内存角度理解指针访问数组的实质

(1) 数组的特点就是:数组中各个元素的地址是依次相连的,而且数组还有一个很大的特点(其实也是数组的一个限制)就是数组中各个元素的类型比较相同。类型相同就决定了每个数组元素占几个字节是相同的(譬如int数组每个元素都占4字节,没有例外)。
(2) 数组中的元素其实就是地址相连接、占地大小相同的一串内存空间。这两个特点就决定了只要知道数组中一个元素的地址,就可以很容易推算出其他元素的地址。

#include<stdio.h>

int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};
    int *p = a;

    //a的值、&a[0]的值(a[0]的地址)
    printf("a = %p\n", a); //a为数组首元素的地址,等同于&a[0]
    printf("&a[0] = %p\n", &a[0]);
    printf("p = %p\n", p);
    
    printf("a[0] = %d\n", a[0]);
    printf("*(a) = %d\n", *(a));

    printf("a[3] = %d\n", a[3]);
    printf("*(a+3) = %d\n", *(a+3));

    printf("*(p+3) = %d\n", *(p+3)); //等同于a[3]
    printf("*(p-1) = %d\n", *(p-1)); //等同于a[-1],越界访问、且数组下标不能为负数
    printf("(p-1) = %p\n", (p-1));

    p = &a[2];
    printf("*(p+1) = %d\n", *(p+1)); //等同于a[3]
    printf("*(p-1) = %d\n", *(p-1)); //等同于a[1]
    printf("*(p+3) = %d\n", *(p+3)); //等同于a[5],越界访问

    return 0;
}

3.6.3、指针和数组类型的匹配问题

(1) int *p; int a[5]; p = a; // 类型匹配
(2) int *p; int a[5]; p = &a; // 类型不匹配。p是int *,&a是整个数组的指针,也就是一个数组指针类型,不是int指针类型,所以不匹配
(3) &a、a、&a[0]从数值上来看是完全相等的,但是意义来看就不同了。

#include<stdio.h>

int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};

    //a, &a, &a[0]
    printf("a = %p\n", a); //数组首元素地址
    printf("&a = %p\n", &a); //数组地址
    printf("&a[0] = %p\n", &a[0]); //数组首元素地址

    printf("a = %d\n", *a);
    printf("*(&a) = %d\n", *(&a)); //warning
    printf("*(&a[0]) = %d\n", *(&a[0]));

    return 0;
}

从意义上来看,a和&a[0]是数组首元素首地址,而&a是整个数组的首地址;
从类型上来看,a和&a[0]是数组中第一个元素的指针,也就是int *类型;而&a是数组指针,是int (*)[5]类型。

3.6.4、总结:指针类型决定了指针如何参与运算

(1) 指针参与运算时,因为指针变量本身存储的数值是表示地址的,所以运算也是地址的运算。
(2) 指针参与运算的特点是,指针变量+1,并不是真的加1,而是加1*sizeof(指针类型);如果是int *指针,则+1就实际表示地址+4,如果是char *指针,则+1就表示地址+1;如果是double *指针,则+1就表示地址+8.
(3) 指针变量+1时实际不是加1而是加1*sizeof(指针类型),主要原因是希望指针+1后刚好指向下一个元素(而不希望错位)。

#include<stdio.h>

int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};
    int *p = NULL;
    p = a;

    printf("*(p+1) = %d\n", *(p+1));
    printf("*((char *)p+1) = %d\n", *((char *)p+1));
    printf("*((int *)(unsigned int *)p+1) = %d\n", *(int *)((unsigned int *)p+1));

    char *p2 = NULL;
    p2 = (char *)p;
    printf("*(p2+1) = %d\n", *(p2+1));

    return 0;
}

返回:C语言指针系列目录

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值