C:数组小结(1)

一、一维数组

1、在内存空间上的存放

一个数组在定义后其在内存中各元素的存放是占据一段连续的地址空间,每个元素需要的空间取决于数组类型:整型需要4字节,字符型需要1字节。

示例:对于int a[100],在内存中占用100×4=400字节空间;对于char c[100]占据内存空间为100字节。

2、数组名

2.1数组名是什么?

首先数组名是数组的名字,所以数组名表示该数组=。=这绝不是废话,这句话非常有助于后面的理解。

其次,数组名还能表示什么?我们都知道,数组名能表示一个地址,如何描述该地址,先直接给出答案:数组名还表示该数组首元素的地址=。=(依然不是废话,而是要注意到:是该数组首元素地址,而不能完全等同于该数组的首地址,后面会细说)。

2.2数组名、数组元素与其取地址的关系

看一个具体例子:int a[10];

先梳理一下,a是数组名,a表示该数组首元素首地址,a[0]表示第0个元素,&a[0]表示首元素的首地址。很自然:a=&a[0]。

继续多想一下,&a是什么?因为a是该数组,所以&a是该数组的首地址。很自然:a=&a[0]=&a.

测试下:

#include<stdio.h>

int main()
{
    int a[10];

    printf("%p
%p
%p",a,&a[0],&a);

    getch();

    return 0;
}

三者在数值上相等,那么三者之间的区别在于什么呢?
首先看&a和&a[0];

a是一个数组,a[0]是数组的一个元素。对两者取地址操作,虽然操作后的数值相同,但两种地址的指向含义是不一样的;&a指向数组单位;&a[0]指向数组元素单位,两者的单位不同,大小也不一样。

说明这里单位空间的含义,假设X为n字节大小的数据,那么&X的含义是(n字节空间的首地址)。对于int m;则&m表示的是一个整型数据大小空间(即4字节)的首地址,(&m+n)表示在m首地址上加n个单位大小的内存空间,设&m=0x10000000H;则&m+1=0x10000004H;&m+10=0x10000028H.

那么在这里,很显然a和a[0]大小不同,a的大小是10×4=40个字节,a[0]大小是4个字节。具体可以通过(&a+n),(&a[0]+n)进行验证测试:

#include<stdio.h>

int main()
{
    int a[10];

    printf("%p
%p
%p
%p
%p
%p",a,&a[0],&a,&a[0]+1,&a[0]+2,&a+2);

    getch();

    return 0;
}

弄清楚&a和&a[0]之后,继续回到数组名a上。

回顾数组名的两层含义:

第一层:表示一个数组。为何说这么明显的一句话不是废话?因为理解了数组名是一个数组,就很轻松可以理解&a:对一个数组取地址,而非对一个数组元素取地址,这可以帮助理解之前&a和&a[0]的区别。

第二层:表示该数组首元素的地址。那么依据之前分析的,(a+n)表示什么?要看(a+n)表示什么,首先要看a表示的是什么,a表示的是首元素地址,那么该地址空间的单位大小就是数组元素的大小,则(a+n)表示数组第n个元素的地址,继续测试:

#include<stdio.h>

int main()
{
    int a[10];

    printf("%p
%p
%p
%p
%p
",a,&a[0],&a,a+1,a+3);

    getch();

    return 0;
}

这里仍然要重点说一下的是:我认为理解&a和&a[0]的相等性和差异是必要而且从逻辑上是合理的,而对于a的第二层表示地址的含义,无法从逻辑上合理得出,而只能去记住:a作为地址含义时,表示的是数组首元素地址,而非数组首地址,并且:数组名非变量,不能作为左值,不能自增自减。从数组定义开始,数组名所表示的地址就已经被固定了,无法修改。

3、指针变量在数组中的应用

回顾数组在内存中的分布:依次连续的一段空间。并且可以通过下标方式去访问数组元素。

对于char c[10];c[0]表示第0个元素,c[i]表示第i个元素。该数组在内存中占据10字节空间,如何细化描述这段空间:该数组在内存中占据10个单元空间,每个单元都是char型数据,为1字节。

定义一个指针变量并使其初始指向字符数组首元素地址:

char *pc=c; 

容易理解:pc+n指向第n个元素,即*(pc+n)==a[n];

同时,一样可以通过对pc的下标来进行访问元素,对于上例中:p[i]=*(p+i)=a[i]=*(a+i);&p[i]=(p+i)=(a+i)=&a[0]+i;

这里说明一下:C编译器当遇见下标时候,比如X[i],先判断X是否表示一个地址(数组名或取地址运算或指针类型均可),再判断X是一个指向什么类型的地址(通过判断类型,来得出单位长度);通过上面两步,设X指向类型单位长度为m,把下标形式转换为(X+i*m)来进行定位。

再引申:

(1)char *pc=c可以替换为char *pc=&c[0]么?

当然可以。

(2)char *pc=c可以替换为char *pc=&c么?替换后(pc+n)表示什么呢?

一样可以替换,(pc+n)依然表示a[n]的地址。

这里有可能疑惑:&c不是表示整个数组的首地址么?。(&c+n)表示的是数组c首地址+n*sizeof(c),那(pc+n)不应该也是数组c首地址+n*sizeof(c)吗?

这里要注意pc是什么?pc是字符指针,所以pc表示的单位大小还是字符型,单字节大小。pc=&c这里只是赋值运算,只是把&c的数值赋给pc。而pc表示的单位大小仍然为单字节。所以(pc+n)依然表示a[n]的地址。

一个关于数组元素访问的综合示例如下:

#include<stdio.h>

int main()
{
    char c[10]="abcde12345";
    char *p1=c;
    char *p2=&c[0];
    char *p3=&c;
    int i;
    int s1=sizeof(c[0]);
    int s2=sizeof(c);
    printf("%d-%d
字符各种访问方式如下
",s1,s2);
    for(i=0;i<10;i++)
    {
        printf("%c--%c--%c--%c--%c--%c--%c--%c
",c[i],*(c+i),p1[i],*(p1+i),p2[i],*(p2+i),p3[i],*(p3+i));
    }
    getch();

    return 0;
}
原文地址:https://www.cnblogs.com/tsembrace/p/3255042.html