28-29.指针和数组分析

目录

指针和数组分析(上)

1.数组的本质

2.指针的运算

指针和数组分析(下)

1.数组的访问方式

2.下标形式VS指针形式

3.a和&a的区别

4.经典面试题

5.数组参数

小结:


 

指针和数组分析(上)

1.数组的本质

  • 数组是一段连续的内存空间
  • 数组空间大小sizeof(arr_type)*arr_size
  • 数组名可看做指向数组第一个元素的常量指针

2.指针的运算

  • 指针之间只支持减法运算
  • 参与减法运算的指针类型必须相同

p1 - p2  <---> ((unsigend int)p1 - (unsigned int)p2)/sizeof(type);

注意:

1.只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素的下标

2.当两个指针的元素在不同一个数组中时,结果未定义

p + n ===p + n*sizeof(type)

指针和数组分析(下)

1.数组的访问方式

  • 以下标的形式访问数组中的元素
  • 以指针的形式访问数组中的元素

2.下标形式VS指针形式

  • 指针以固定的增量在数组中移动时,效率高于下标形式
  • 指针增量为1且具有硬件增量模型时,效率更高
  • 下标形式与指针形式的转换

a[n] <-->*(a+n)<-->*(n+a)<-->n[a]

注意:

现代编译器的生成代码优化率已提高,在固定增量时,下标形式效率和指针形式相当;但从可读性和代码维护的角度来看,下标形式更优。

示例:

main.c

#include <stdio.h>
 
int main()
{
    //extern int a[];//编译运行没问题
extern int* a;
    
    printf("&a = %p\n", &a);//取四个字节的地址
    printf("a = %p\n", a);//取a本身的地址,0x01其实就是a[1]的值
    printf("*a = %d\n", *a);//0x01是操作系统使用的地址,段错误。
 
    
    return 0;
}

ext.c

int a[] = {1, 2, 3, 4, 5};

3.a和&a的区别

a为数组首元素的地址

&a为整个数组的地址

a和&a的区别在于指针运算

4.经典面试题

#include <stdio.h>
 
int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int* p1 = (int*)(&a + 1); 
    int* p2 = (int*)((int)a + 1);//指向的是a[0]的第二个字节
    int* p3 = (int*)(a + 1);
    
    printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);//5,随机数,3
    //p2[0]就是a[0]的后三个字节+a[1]的第一个字节(小端模式)
    return 0;
}

5.数组参数

数组作为函数参数时,编译器将其编译成对应的指针

结论:一般情况下,当定义的函数中有数组参数时,需要定义另一个参数来标识数组的大小。

数组作函数参数时,会退化为一个指针。

void func1(char a[5])

{

    printf("In func1: sizeof(a) = %d\n", sizeof(a));//打印出来的是4而不是5,说明会退化为一个指针

    *a = 'a';

    a = NULL;

}

小结:

  • 数组和指针仅使用方式相同
    • 数组名本质不是指针
    • 指针本质不是数组
  • 数组名并不是数组的地址,而是数组首元素的地址
  • 函数的数组参数退化为指针

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值