C语言指针和数组分析(下)

数组名可以当作常量指针使用,那么指针是否也可以当作数组名来使用呢?

1.不同形式访问元素

以下标的形式访问数组的元素
int a[5]={0};
a[1]=3;
以指针的形式访问数组的元素
int a[5]={0};
*(a+1) = 3;

下标形式与指针形式的转换:
在这里插入图片描述

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

是否可以使用指针当数组名使用,编程来看结果

#include <stdio.h>

int main()
{
    int a[5] = {0};
    int* p = a;
    int i = 0;
    
    for(i=0; i<5; i++)
    {
        p[i] = i + 1;//把指针当作数组名来使用
    }
    
    for(i=0; i<5; i++)
    {
        printf("a[%d] = %d\n", i, *(a + i));
    }
    
    printf("\n");
    
    for(i=0; i<5; i++)
    {
        i[a] = i + 10;
    }
    
    for(i=0; i<5; i++)
    {
        printf("p[%d] = %d\n", i, p[i]);
    }
    
    return 0;
}

在这里插入图片描述
数组名可以当作常量指针使用,那么指针是否也可以当作数组名来使用呢?
从结果来看,是可行的。

2.数组和指针不同

两个文件,一个test.c,一个ext.c

#include <stdio.h>

int main()
{
    extern int* a;
    //打印出数组首地址的地址值
    printf("&a = %p\n", &a);
    //打印指针变量a所存的地址,a=1;
    //打印指针的值就是到自己的地址去取四个字节,而此处存的是0x01;
    printf("a = %p\n", a);
    //到a所保存的地址值0x01低地址去取数据,会产生段错误,该低地址是保留给操作系统使用的
    printf("*a = %d\n", *a);

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

编译运行 :
在这里插入图片描述
可以得知,extern int* a;extern int a[];是不同的,如果是声明为a[],那么打印出来的&a和a是同个地址,即数组的首地址,*a是第一个元素的值。所以我们知道,数组名只是可以看成常量指针,而不是真的是指针。

3.a和&a的区别

a为数组首元素的地址,&a为整个数组的地址,a和&a的区别在于指针运算。
在这里插入图片描述
+1增加的步长所示不一样的,上面的是增加一个元素的大小,下面的是增加的是整个数组地址的大小。

4.指针运算经典问题

下面的程序输出什么,为什么?

#include <stdio.h>

int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int* p1 = (int*)(&a + 1); //数组的地址+1,移动一整个数组大的长度大小,即a[5]
    int* p2 = (int*)((int)a + 1);//把a转整型+1,得到一个数组内的地址,已经不是指针运算
    int* p3 = (int*)(a + 1);//指向第二个元素
    
    printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);
    //x  2 2
    return 0;
}

// A. 数组下标不能是负数,程序无法运行
// B. p1[-1]将输出随机数,p2[0]输出2, p3[1]输出3
// C. p1[-1]将输出乱码, p2[0]和p3[1]输出2

编译运行的答案是:
在这里插入图片描述

p1[-1]输出了5,p1相当于a[5],p1[-1] ==>*(p1-1),a[5]指针-1运算,得到a[4],也就是5。
p2[0]已经不是指针运算,得到的是一个数组地址内的值,在小端系统下,示例如下图所示,十进制33554432。
p3[1]输出3,原因在于,p3[0]指向的就是a[1],所以开始算的位置是2是p3[0],3是p3[1]。在这里插入图片描述

5.数组参数

数组作为函数参数时,编译器将其编译成对应的指针
在这里插入图片描述

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

虚幻的数组参数
实例分析,说明数组参数会退化为指针

#include <stdio.h>

void func1(char a[5])
{
    printf("In func1: sizeof(a) = %d\n", sizeof(a));//打印数组的大小,5*1=5
    
    *a = 'a';
    
    a = NULL;//如果是数组,这里是错误的,数组名不可被赋值
}

//这个函数同上,只是传进去的数组大小没有写
void func2(char b[])
{
    printf("In func2: sizeof(b) = %d\n", sizeof(b));
    
    *b = 'b';
    
    b = NULL;
}

int main()
{
    char array[10] = {0};
    
    func1(array);
    
    printf("array[0] = %c\n", array[0]);
    
    func2(array);
    
    printf("array[0] = %c\n", array[0]);
    
    return 0;
}

编译通过,说明了传进去的char a[5]参数和char b[]参数已经被转为了指针,因为可以运行 a= NULL;和 b = NULL;
在这里插入图片描述
而且打印出来的参数的大小为8(64位系统),且 * a和* b可以修改array数组里的值,很明显是指针类型。

6.小结

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值