(一)数组的内存布局

对于语句int a[5]; 我们明白这里定义了一个数组,数组里有5个元素,每一个元素都是int类型,我们可以用a[0],a[1]等访问数组里的元素,但是这些元素的名字就是a[0],a[1]吗?

请看下面的内存布局图:

如上图所示,当我们定义一个数组int a[5],编译器根据指定的数组元素以及数组元素类型分配内存,分配内存的大小是:元素类型大小*元素个数,并且把这个空间命名为a,a[0],a[1]是数组a的元素,但不是数组元素的名字,数组的每一个元素是没有名字的。

我们再来看看sizeof关键字的几个问题:

sizeof(a)的值是sizeof(int)*5,32位系统下是20;

sizeof(a[0])的值是sizeof(int),32位系统下是4;

sizeof(&a[0])的值在32位系统下为4,这很好理解,取首元素a[0]的首地址;

sizeof(&a)的值也是4,取数组a的首地址。

程序:

 #include <stdio.h>

 void main()
{
int a[] = {, , , , };
printf("sizeof(a):%d\n", sizeof(a));
printf("sizeof(a[0]):%d\n", sizeof(a[]));
printf("sizeof(&a[0]):%d\n", sizeof(&a[]));
printf("sizeof(&a):%d\n", sizeof(&a));
}

程序输出:

 sizeof(a):
sizeof(a[]):
sizeof(&a[]):
sizeof(&a):

(二)省政府和市政府的区别-&a和&a[0]

我们首先在程序中把&a和&a[0]的值打印出来:

 #include <stdio.h>

 void main()
{
int a[] = {, , , , };
printf("&a:%d, &a[0]:%d\n", &a, &a[]);
}

其结果是: &a:, &a[]:

我们发现这两者的值是一样的,那么这两者有什么区别呢?a是整个数组,而a[0]是数组首元素,因此&a是整个数组首地址,&a[0]是数组首元素地址,举个例子更好理解:湖南的省政府在长沙,而长沙的市政府也在长沙,二者地址一样,但代表的意义却完全不同。

(三)数组名a作为左值和右值的区别

先来理解下左值和右值:

简而言之,出现在赋值符号“=”左边的就是左值,而右边则是右值,

比如x=y;

左值:在这个上下文环境中,编译器认为x的含义是x所代表的地址,这个地址只有编译器知道,在编译的时候确定,编译器在一个特定的区域保存这个地址,我们完全不必考虑这个地址保存在哪里;

右值:在这个上下文环境中,编译器认为y的韩式是y所代表的地址里面的内容。这个内容是什么,只有到运行时才知道。

既然明白了左值和右值的区别,下面就讨论下数组作为左值和右值的区别:

当a 作为右值的时候代表的是什么意思呢?很多书认为是数组的首地址,其实这是非常错误的。a 作为右值时其意义与&a[0]是一样,代表的是数组首元素的首地址,而不是数组的首地址。这是两码事。但是注意,这仅仅是代表,并没有一个地方(这只是简单的这么认为,其具体实现细节不作过多讨论)来存储这个地址,也就是说编译器并没有为数组a分配一块内存来存其地址,这一点就与指针有很大的差别。

a 作为右值,我们清楚了其含义,那作为左值呢?
a 不能作为左值!这个错误几乎每一个学生都犯过。编译器会认为数组名作为左值代表的意思是a 的首元素的首地址,但是这个地址开始的一块内存是一个总体,我们只能访问数组的某个元素而无法把数组当一个总体进行访问。所以我们可以把a[i]当左值,而无法把a当左值。其实我们完全可以把a 当一个普通的变量来看,只不过这个变量内部分为很多小块,我们只能通过分别访问这些小块来达到访问整个变量a 的目的。

(四)a和&a的区别

对于数组int a[5];若我们要定义指针变量接受a,我们可以这样做 int *pa = a; 但是我们若要定义指针接受&a,使用int *pa = &a却不行,编译器报错a value of type "int(*)[5]" cannot be assigned to an entity of type "int *",从这个报错我们知道&a的类型是int(*)[5],这是一个指向数组指针,数组里有5个元素。

为了看到a,&a的区别,

我们将a和&a的值打印出来: printf("a:%d, &a:%d\n", a, &a); ,并将a+1和&a+1打印: printf("a+1:%d, &a+1:%d\n", a+, &a+);

其结果是:

 a:, &a:
a+:, &a+:

从上面两行的打印我们可以看出,数组名a里存放的是数组首元素的地址,而&a是整个数组的地址,这两者在值上是一样的,但是a和&a 做+1操作时,a+1增加的是一个元素的大小4,而&a+1增加的是整个数组的大小20。

C Program进阶-数组的更多相关文章

  1. C Program进阶-二维数组动态内存开辟

    对于二维数组,我们知道可以用Type ArrayName[Row][Colume]的方式来定义,这是一种静态内存开辟的方式,程序在编译的时候就为该数组分配了空间,而且行和列大小也是指定的.这篇文章里我 ...

  2. 移动app接口编程技术-学习实现之PHP进阶 数组

    数组创建,初始化 <?php //请创建一个数组变量arr,并尝试创建一个索引数组 /** * 不带初始值的创建.创建后赋予值 * 注:下标一定是整数 */ $arr = array(); $a ...

  3. C语言字符数组和字符串

    用来存放字符的数组称为字符数组,例如: char a[10]; //一维字符数组 char b[5][10]; //二维字符数组 char c[20]={'c', ' ', 'p', 'r', 'o' ...

  4. 【Linux进阶】使用grep、find、sed以及awk进行文本操作

    目录 一.元字符 二.grep命令 1. 过滤出包含某字符串的行 2. 过滤出以某字符串开头(结尾)的行 3. 过滤出包含某字符串及其相邻的行 4. 过滤出不包含某关键字的行 5. 过滤出包含多个字符 ...

  5. .NET基础拾遗(3)字符串、集合和流

    Index: (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基础 ...

  6. .NET基础拾遗(3)字符串、集合和流3

    三.流和序列化 3.1 流概念及.NET中常见流 无论什么信息,文字,声音,图像,只要进入了计算机就都被转化为数字,以数字方式运算.存储.由于计算机中使用二进制运算,因此数字只有两个:0 与 1,就是 ...

  7. 用commander.js构建自己的脚手架工具

    随着前端技术的发展,工程化逐渐成为了一种趋势.但在实际开发时,搭建项目是一件很繁琐的事情,尤其是在对一个框架的用法还不熟悉的时候.于是很多框架都自带一套脚手架工具,在初始化前端项目的时候就可以不用自己 ...

  8. Pascal数据结构与算法

    第一章 数据结构与算法的引入 1.1 数据结构的基本概念 一. 学习数据结构的意义 程序设计 = 数据结构 + 算法 目前,80%的待处理的数据具有“算法简单”(四则运算.检索.排序等),“对象复杂” ...

  9. 3012C语言_数据

    第二章 数据 2.1 数据类型 2.1.1 数据类型决定 1. 数据占内存字节数 2. 数据取值范围 3. 其上可进行的操作 2.2基本数据类型 2.2.1分类 基本类型 类型 符号 关键字 字节 1 ...

随机推荐

  1. Linux 学习第四天

    Linux学习第四天 一.常用命令 1.tar  (压缩.解压) A.添加压缩包  tar czvf 压缩包名称.tar.gz 源文件 B.添加压缩包  tar cjvf 压缩包名称.tar.bz2 ...

  2. layui layer.open() 弹层开启后 Enter回车 遮罩层无限弹处理

    解决方案: 增加success回调及其内容 如下: layer.open({ title:'更新论坛信息', type: 1, skin: 'layui-layer-rim', area: ['500 ...

  3. html+css3 实现各种loading效果

    效果见下图 代码: 建议直接去本人github上浏览代码 https://github.com/wuliqiangqiang/loading <!DOCTYPE html> <htm ...

  4. python__基础 : 多继承中方法的调用顺序 __mro__方法

    在多继承中,如果一个子类继承了两个平级的父类,而这两个父类有两个相同名字的方法,那么一般先继承谁,调用方法就调用先继承的那个父类的方法.如: class A: def test(self): prin ...

  5. php连接数据库(一)

    1.php链接数据库: 1.链接数据库 2.判断是否连接成功 3.设置字符集 4.选择数据库 5.准备SQL语句 6.发送SQL语句 7.处理结果集 8.释放资源(关闭数据库) $result = m ...

  6. Python学习笔记四:列表,购物车程序实例

    列表 切片 中括号,逗号分隔,可以一次取出多个元素,起始位置包括,结束位置不包括(顾头不顾尾) 如果取最后一个,而且不知道列表长度,可以使用负数(-1是最后一个,以此类推) 如果取最后几个,记住从左往 ...

  7. 运用busybox构建最小根文件系统

    平台:vmware下ubuntu14.04前期准备:安装交叉编译环境arm-linux-gcc-4.5.1;下载完成BusyBox 1.23.2一.busybox构建1.make menuconfig ...

  8. Kylin 几个sql报错原因 汇总

    Can't create EnumerableAggregate! while executing SQL由distinct count引起的错误 null while executing SQLjo ...

  9. NoSQL入门第四天——事务与主从复制

    一.Redis的事务 1.是什么 可以一次执行多个命令,本质是一组命令的集合.一个事务中的 所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞 (更多请参见官网事务介绍) 2.能干什 ...

  10. Android stdio build.gradle buildscript 里面的repositories 和allprojects里面 repositories 的区别

    第一段 buildscript 里面的 repositories 表示只有编译工具才会用这个仓库. 比如 buildscript 里面的 dependencies classpath 'com.and ...