(一)数组的内存布局

对于语句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. vector 定义的二维数组的遍历

    之前我们分享了STL的一些容器,再介绍vector中只介绍了二维的vector的定义并没有说二维的vector怎么遍历,那么我们今天就来看下二维的vector怎么遍历 看下面的代码吧. #includ ...

  2. centos7 php7 动态编译mysqlnd: configure: error: Cannot find OpenSSL's <evp.h> 错误解决

    开始以为是没有安装openssl, openssl-devel,安装后发现还是提示这个错误,搜索了一下evp.h,这个文件也存在.GOOGLE 了一下,在stackoverflow,找到了答案,原来是 ...

  3. chrome调试微信

    打开微信,设法打开网址 http://debugx5.qq.com (推荐直接把这个网址发给文件传输助手,然后就可以直接打开链接了) 在打开的网页中选择 [信息]->[TBS settings] ...

  4. Ubuntu中 MySQL 的中文编码问题

    使用Ubuntu在安装好MySQL数据库之后,如果直接创建数据库,再创建数据表,那么是无法向字段插入中文的,会报Incorrect string value错误. c实现编码设置的两种方法: (1)动 ...

  5. 【Hive五】Hive函数UDF

    Hive函数 系统自带的函数 查看系统自带的函数 查看系统自带的函数 show functions; 显示自带的函数的用法 desc function upper; 详细显示自带的函数的用法 desc ...

  6. 树莓派驱动DHT22

    树莓派-DHT22测量湿度 一般的温湿度传感器有dht11和dht22,dht11比较便宜,dht22比dht11贵好几倍,自然测量的准确度肯定是dht22高一些.追求更高精准度的可以使用SHT1x. ...

  7. python3 练习题100例 (一)

    断断续续的学了很久的python,有很多又忘记了.从今天开始用实例再进行一次学习,并记录.本人小白一个,请大家多多指教. #!/usr/bin/env python3 # -*- coding: ut ...

  8. Python学习:4.运算符以及数据类型解析

    运算符 一.算数运算: 二.比较运算: 三.赋值运算 四.逻辑运算 五.成员运算 基本数据类型 一.Number(数字) Python3中支持int.float.bool.complex. 使用内置的 ...

  9. ggnetwork

    ggnetwork ggnetwork PeRl 简介 ggnetwork是根据ggplot2的语法,开发的用于网络图可视化的包.虽然igraph是优秀的network处理包,但是在可视化方面依然是弱 ...

  10. 分布式专题(二)——Zookeeper的ZAB协议介绍