数组与指针分析

指针和数组(上)

专题四:指针和数组(上)。包括以下章节:

  • 指针基础
  • 数组基础
  • 数组与指针分析
  • C语言中的字符串

数组的本质

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

指针的运算

  • 指针是一种特殊的变量,与整数的运算规则为:
    p + n; <==> (unsigned int)p + n * sizeof(*p);
  • 结论: 当指针p指向一个同类型的数组的元素时:p+1将指向当前元素的下一个元素;p-1将指向当前元素的上一 个元素。

3-1.c

#include<stdio.h>

int main()
{
    int a[5] = {0};

    //a=F70BE2B0
    //根据公式:a+1 = F70BE2B0 + 1 * sizeof(*a) = F70BE2B4
    //*a是a数组第一个元素的值0,是int型, sizeof(*a) = 4
    printf("%0X, %0X\n", (unsigned int)(long)a, (unsigned int)(long)(a+1));

    return 0;
}

结果:
这里写图片描述

  • 指针之间只支持减法运算,且必须参与运算的指针类型必须相同
    p1 – p2; ( (unsigned int)p1 - (unsigned int)p2) / sizeof(type);

    • 只有当两个指针指向同一个数组中的元素时,指针 相减才有意义,其意义为指针所指元素的下标差
    • 当两个指针指向的元素不在同一个数组中时,结果未定义(1,一个在栈上定义,一个在堆上定义;2,计算出来的是相差字节数)

3-2.c

#include <stdio.h>
#include <malloc.h>

int main()
{
    char s1[] = {'H', 'e', 'l', 'l', 'o'};
    int i = 0;
    char s2[] = {'W', 'o', 'r', 'l', 'd'};
    char* p0 = s1;
    char* p1 = &s1[3];
    char* p2 = s2;
    int* p = &i;

    printf("%d\n", p0 - p1);
    printf("%d\n", p0 + p2);
    printf("%d\n", p0 - p2);
    printf("%d\n", p0 - p);
    printf("%d\n", p0 * p2);
    printf("%d\n", p0 / p2);

    return 0;
}

指针的比较

  • 指针也可以进行关系运算
  • 指针关系运算的前提是同时指向同一个数组中的元素
  • 任意两个指针之间的比较运算(==, !=)无限制

3-3.c

#include <stdio.h>
#include <malloc.h>

#define DIM(a) (sizeof(a) / sizeof(*a))

int main()
{
    char s[] = {'H', 'e', 'l', 'l', 'o'};
    char* pBegin = s; //首元素地址
    char* pEnd = s + DIM(s);//'o'下一个地址
    char* p = NULL;

    for(p=pBegin; p<pEnd; p++)
    {
        printf("%c", *p);
    }

    printf("\n");

    return 0;
}

结果:
这里写图片描述

数组的访问

//以下标的形式访问数组中的元素
int main()
{
    int a[5];

    a[1] = 3;
    a[3] = 5;

    return 0;
}

//以指针的形式访问数组中的元素
int main()
{
    int a[5];

    *(a+1) = 3;
    *(a+3) = 5;

    return 0;
}
  • 从理论上而言,当指针以固定增量在数组中移动时,其效率高于下标产生的代码
  • 当指针增量为1且硬件具有硬件增量模型时,表现更佳
  • 注意: 现代编译器的生成代码优化率已大大提高,在固定增 量时,下标形式的效率已经和指针形式相当;但从可 读性和代码维护的角度来看,下标形式更优。
#include <stdio.h>
#include <time.h>

int main()
{
    clock_t start;
    clock_t end;
    int a[10000];
    int b[10000];
    int* pEnd = &a[10000];
    int* pa = NULL;
    int* pb = NULL;
    int i = 0;
    int k = 0;

    start = clock();

    for(k=0; k<10000; k++)
    {
        for(i=0; i<10000; i++)
        {
            b[i] = a[i];
        }
    }

    end = clock();

    printf("Index Timing: %d\n", end - start);

    start = clock();

    for(k=0; k<10000; k++)
    {
        for(pa=a, pb=b; pa<pEnd;)
        {
            *pb++ = *pa++;
        }
    }

    end = clock();

    printf("Pointer Timing: %d\n", end - start);

    return 0;
}

结果:
这里写图片描述

a和&a的区别

  • a为数组是数组首元素的地址
  • &a为整个数组的地址
  • a和&a的意义不同其区别在于指针运算
  • a + 1 <==> (unsigned int)a + sizeof(*a)
  • &a + 1 <==> (unsigned int)(&a) + sizeof(*&a)

实例分析3-1

#include<stdio.h>

int main()
{
    int a[5] = {1,2,3,4,5};
    int* p1 = (int*)(&a + 1); //p1的值是数组中最后一个元素下一个地址, &a[4] + 4
    int* p2 = (int*)((int)a + 1);//p2的值是数组第一个元素的地址+1字节; &a[0] + 1
    int* p3 = (int*)(a + 1);//p3的值是数组第一个元素的地址+4字节,&a[0] + 4 = a[1]

    //p1[-1]:等价于*(p1-1)等价于*((unsigned int)p1-sizeof(int)) = *(&a[4] + 4 - 4) = *(a[4]) = a[4] 等于5
    //p2[0]:等价于*p2
    //p3[1]:等价于*(p3+1)等价于*((unsigned int)p3+1*sizeof(int)) = *(&a[1] + 4) = *(&a[2]) = a[2] = 3
    printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);

    return 0;
}

数组参数

  • C语言中,数组作为函数参数时,编译器将其编译成对应的指针
  • void f(int a[]); <==> void f(int* a);
  • void f(int a[5]); <==> void f(int* a);
void f(int a[1000])
{
    //打印结果:8。看做了指针int* a, sizeof(a) = 8(64位系统)
    printf("%lu\n", sizeof(a));
}

int main()
{
    int a[5] = {0};

    f(a);//a[5]与f函数参数a[1000]不同,但编译器不报错

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

指针和数组的对比

  • 数组声明时编译器自动分配一片连续内存空间
  • 指针声明时只分配了用于容纳指针的4字节空间
  • 在作为函数参数时,数组参数和指针参数等价
  • 数组名在多数情况可以看做常量指针,其值不能改变
  • 指针的本质是变量,保存的值被看做内存中的地址

数组和指针详细资料可以搜索:

数组与指针详情:
http://blog.csdn.net/yby4769250/article/details/7294718
数组名与指针的区别:
https://wenku.baidu.com/view/678d1925a5e9856a561260b1.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值