【C语言复习(十二)】数组基础

1、数组的概念

数组是相同类型的变量的有序集合;如int num[5];


2、数组地址与数组名

数组名代表数组首元素的地址;

数组的起始地址需要使用取地址符&才能得到;

数组首元素的地址值与数组的起始地址值相同,但却是不同的两个概念,如上图中所示;

3、数组名

数组名通常可以看作是一个常量指针,即它不能作为左值被赋值,只能作为右值赋值给其他变量;

数组名“指向”的是内存中数组首元素的位置(即首元素地址);

只有在下列场合中,数组名不做为常量指针:

数组名作为sizeof操作符的参数;数组名作为&运算符的参数;

 

4、定义为指针,声明为数组:(指针和数组并不相同)

分析如下示例:
/*another.c*/
char* p="Hello World";


/*test.c*/
#include <stdio.h>
extern char p[];
int main()
{
    printf("%s\n",p);
    return 0;
}


注意观察,首先在another.c文件中定义一个字符指针变量p,并指向一字符串常量;然后test.c文件中把p声明为外部变量,表示它定义在其它文件中,但这里的声明和它的定义稍微不同,声明成了一个字符数组,思考一下,运行程序能打印出”Hello World”吗??
运行结果:


不出意外,都会看到这么一串乱码的字符,这是为什么呢?为什么输出的不是”Hello World”??

简单的分析:

首先编译器在编译another.c文件是,发现定义了变量,那么为此变量分配内存空间,并完成初始化,并且编译器会在符号表中加入此变量:


然后编译test.c,发现p被声明为外部变量,且为字符数组,所以编译器把从变量p的起始地址开始的一段内存空间当作数组空间:注:这里p变量的值实际上就是Hello World字符串常量的起始地址!

 

最后运行程序,我们尝试输出字符数组p内的值,可以发现,实际上这里输出的却是从0xAABBCC00地址开始的值,而我们实际想输出的却是内存0xBBCCDD00单元开始的值;所以结果显然不是Hello World

详细分析:

要论述这个问题的本质,实际上还要明白,指针变量在使用时,是要经过一次寻址操作的,比如上面的指针变量char* p;如果使用它输出字符串,那么会先读取出指针变量中存放的地址值,再从此地址开始读取我们想要输出的值,而对于数组,比如char p[];要输出它的值,则是直接从数组的起始地址开始读取值;

 

手动寻址,改正错误??

既然上面分析了,数组的操作中不存在寻址操作,那么我们可以手动完成它!

看上面的两张图可知,此时数组变量p的前四个内存单元实际上存储的是一个指针值,该指针值是Hello World字符串常量的存储地址!而此时p作为一个数组,那么数组名p就代表该数组的首元素地址,利用这一点,直接将p强制转换为一个无符号整形指针,然后读取这个指针的值,再作为char*类型输出,就能得到Hello World

做如下的改动:

printf("%s\n",(char*)(*((unsigned int*)p)));

这样就能输出Hello World了!

为什么能正确输出??为什么要用int*??

如果我们改成:

printf("%s\n",(char*)(*((char*)p)));

就不能读取到Hello World!这是为什么呢??难到一定要用int*??仔细分析一下此语句:
首先,当前p应该是一个字符数组,那么p就代表数组的首元素地址,它的值也等于数组的起始地址,假设为:0xAABBCC00,因为在编译another.c文件时,p为指针变量,并进行了初始化,所以它的0xAABBCC00--0xAABBCC03这个四个字节应该保存的是Hello World的真实地址,回到test.c,那么当前字符数组的前四个字节空间存放的应该是一个无符号整形值,也就是Hello World存储地址;现在p的值为0xAABBCC00,我们进行强制类型转换:(unsigned int*)p

这时候我们所得到的,其实是另外一个unsigned int*指针,该指针指向了当前字符数组p的起始地址,也就是:0xAABBCC00;便于理解,可以这样写:

    unsigned int* L=(int*)p;
    printf("%s\n",(char*)(*L));

指针L指向了当前字符数组的起始地址,且认为0xAABBCC00--0xAABBCC03四个字节存放的是一个无符号整数,而这个无符号整数,就是我们迫切需要的Hello World 存储地址,假设为0xBBCCDD00,即是当前指针变量L中存放的地址为:0xBBCCDD00,然后我们再对L指针做*运算,便可访问0xBBCCDD00地址段,再把它转换为char*类型指针,最后用%s的格式输出,就能得到Hello World了!

如果对p的强制转换写作(char*)p,那么得到的指针虽也指向当前字符数组的起始地址,但是它将把这部分内存中的值当作一个字节一个字节的字符,从而无法通过*((char*)p)得到原Hello World的存储地址,只能得到一个字节的数据;

5、数组小结

数组是一片连续的内存空间;

数组的起始地址和数组首元素地址值相同,意义不同;

数组名在大多数情况下被当成常量指针处理;

数组名不是指针,在外部声明时不能混淆;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值