当前课程知识点:C++语言程序设计基础 > 第6章 数组、指针与字符串(一) > 数组的定义与初始化 > 数组的储存与初始化
数组的存储与初始化
数组元素在内存中顺次存放,它们的地址是连续的。元素间物理地址上的相邻,对应着逻辑次序上的相邻。
例如:
在定义数组时给出数组元素的初始值。
列出全部元素的初始值
例如:static int a[10]={0,1,2,3,4,5,6,7,8,9};
可以只给一部分元素赋初值
例如:static int a[10]={0,1,2,3,4};
在对全部数组元素赋初值时,可以不指定数组长度
例如:static int a[]={0,1,2,3,4,5,6,7,8,9}
按行存放
例如: float a[3][4];
可以理解为:
其中数组a的存储顺序为:
a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23
将所有初值写在一个{}内,按顺序初始化
例如:static int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12
分行列出二维数组元素的初值
例如:static int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
可以只对部分元素初始化
例如:static int a[3][4]={{1},{0,6},{0,0,11}};
列出全部初始值时,第1维下标个数可以省略
例如:static int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
或:static int a[][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
注意:
如果不作任何初始化,内部auto型数组中会存在垃圾数据,static数组中的数据默认初始化为0;
如果只对部分元素初始化,剩下的未显式初始化的元素,将自动被初始化为零;
现在我们来看一个用数组存放Fibonacci数列的例子。
#include <iostream>
using namespace std;
int main() {
int f[20] = {1,1}; //初始化第0、1个数
for (int i = 2; i < 20; i++) //求第2~19个数
f[i] = f[i - 2] + f[i - 1];
for (i=0;i<20;i++) { //输出,每行5个数
if (i % 5 == 0) cout << endl;
cout.width(12); //设置输出宽度为12
cout << f[i];
}
return 0;
}
运行结果:
大家好
欢迎回来继续学习
C++语言程序设计
这一节
我给大家介绍
数组的存储与初始化
那么一维数组的存储呢
它是在内存中
按次序存放的
元素与元素之间
它的地址是连续的
也就是说
是通过元素之间
物理地址上的相邻关系
来体现出
数组元素逻辑次序上的相邻关系
我们看这样一个例子
这个示意图
比如说我们定义了一个数组a
那么数组a里面的各个元素
在内存中它是怎么存放的呢
它就一个挨一个
这么连续存放的
中间不会有空档字节
那数组名
其实就是数组元素的首地址
也就是
这一组元素它的起始地址
所以说呢
一旦你定义好一个数组以后
数组名它就是一个常量了
一个地址类型的常量
还有地址类型吗
我们前面学过的那么多
数据类型里面
没有包括地址类型
在这一章稍后
我们就会学习地址类型
其实也就是叫做指针类型
那么a里面呢
这个数组名a里面
存放的就是一个常量
就是数组的起始地址
所以我们要很小心
千万不要试图给数组名
重新赋值
因为它是常量
它存着数组的起始地址
是不可改变的
所以也是不可以重新被赋值的
接下来呢
我们来学习
如何对一维数组进行初始化
对数组初始化
也就是说
我们在定义数组的时候
要给予它初始值
我们来看一维数组初始化
可以有这样几种方式
第一种方式
是列出全部元素的初始值
看看在这个数组定义之后呢
写一个等于号
然后在一对大括号中
用逗号分隔
列出了这个数组的
全部十个元素的初始值
那我们如果说
不想给全部的元素赋初始值
只想给一部分元素初始化
是不是可以呢
也可以
我们看第二个
是只给一部分元素初始化的情况
这里只列出了
前五个元素的初始值
如果我们已经列出了
全部元素的初始值呢
那就可以不指定数组的长度了
所以在第三种情况我们看
定义一个数组的时候
给出了全部的元素初始值
所以方括号里面的元素个数
也就是下标个数
就可以不写了
这时候编译器呢
会按照你给出的初始值个数
去确定数组元素的个数
接下来
我们再来学习
二维数组的存储
看看二维数组在内存中
它是怎么存储的呢
它也是依次连续存储的
实际上我们可以将二维数组
理解成
由一维数组构成的数组
我们看这个示意图
比如说
我们定义一个
float类型的二维数组a
它有三行四列
那么每一行呢
都可以看作是一个一维数组
我们知道
如果你要访问一个
二维数组的元素
那数组名之后
应该有两个方括号下标
指出它的行下标和列下标
你才能定位到一个具体的元素
但是现在如果我们只写一个下标
只写第一维的下标
那表示什么呢
如果我们只写a[0]的话
那就表示0行的首地址
我们写a[1]
就表示一行的首地址
a[2]表示二行的首地址
所以呢
a[0] a[1] a[2]
它本身又是地址
它是行的首地址
那么一个二维数组
实际上就是由一维数组这些行
构成的数组
这样我们就不难理解
二维数组在内存中的存放形式
是什么呢
是按行存储
具体到这个例子
它是先存储零行
再存储一行
再存储二行
这样依次存储的
那么如果是多维数组呢
就依此类推
对于二维数组
在定义的时候
我们能不能也给它的元素
设置初始值呢
也可以
这就是二维数组的初始化问题
我们来看
我们对二维数组
进行初始化的时候
也是可以有这样几种方式
一种呢
是列出全部的初始值
列出全部初始值的时候
那么编译器
就会按照你定义的行列结构
以及全部的初始值
将这些值
按照一行一行的次序
依次对应上去
如果列出来的全部初始值
就这么平铺直叙地列在这儿
那显然看起来就不那么直观
虽然对于编译器来说
这个无所谓的
它不会对应错
但是对于我们人
程序员自己看起来
就不那么清楚了
所以我们还可以对它进行分组
在大括号之内
按照行
每行一组
再用大括号给它界定起来
给它包括起来
这样的话
不仅看起来一目了然
比较清楚
而且可以用这种方式
只给部分元素进行初始化
我们知道不管是几维数组
你在这种初始化列表中
列出所有的初始值
进行初始化的时候
你必须连续列出元素的初始值
虽然你可以只给前若干个元素
指定初始值
但是你不能跳跃着
我给一三五七个元素指定初始值
那是不可以的
这样的话
如果
对二维数组进行初始化的时候
我们不想给出所有初始值
而是想比如说
给出零行的首元素初始值
一行的前两个元素初始值
二行的前三个元素初始值
那么
对于整个一个初始化序列来说
它中间是空掉了很多
因为它按行初始化
首先你零行的首元素有初始值了
那后面几个元素没有初始值
那就跳过去了
如果你只给一个
不分组的初始化列表的话
初始值列表的话
那你是不能跳跃着给初始值的
不能有空的逗号
但是如果你对它进行分组了
你就可以在每一组中
只给前若干元素指定初始值
这样我们就达到了
给各个行的前若干元素
指定初始值的这样的效果
还有呢
如果你在初始化的时候
列出了全部的初始值
下标的个数也有可以省略的地方
但是二维数组
你不能把两个维的下标个数
都省略了
那你说我有十二个初始值
两个下标个数我都不写
那编译器真的不知道
你想是哪一维是几个下标了
所以语法规定呢
是第一维的下标个数可以不写
所以呢
那个三行四列
第一三我们就可以不写了
实际上呢
我们有的时候定义数组
会不介意它的初始值
因为事后可能马上就从
键盘去读入数据了
或者从文件读入数据了
或者就是用它来存储
某一个计算的结果
所以不介意它的初始值
所以有的时候确实
我们程序员会定义数组
但是不给它初始化
如果定义一个数组的时候
不给它进行初始化
它的初始值会是什么呢
如果是一个局部作用域里面的
非静态数组
那么不初始化的话
它的初始值就是垃圾数据
不可靠的
不可使用的
如果像我们这几个例子里面
列出来的
是静态数组
那不初始化它的话
数值型的数据会默认初始化为0
如果你只对数组的一部分元素
进行初始化
比如说对它前若干元素
进行初始化
那剩下没初始化那些元素
会是什么呢
都会自动初始化为0
现在我们来看一个
用数组来存放
Fibonacci数列的例子
这个例题呢
也是一个典型的结合数组
和循环来使用的例题
求Fibonacci数列的前20项和
将结果存放于数组中
我们知道Fibonacci数列
它每一项是前两项之和
所以数列的这些项之间
依次变化的规律
是固定的
既然我们知道了
这个依次变化的规律
我们就可以用for循环
依次处理数组的各个元素
也就是依次求出
这个数列的各个项
那由于每一项是前两项之和
所以我们应该首先
在定义数组的时候
就把它最开头的两个项
做好初始化
分别初始化下标为0
和1的这两个数
这两个元素都是1
那接下来呢
我们这个for循环呢
从数组下标等于2的地方开始
然后控制它到小于20的地方
因为前20项
最大下标是19
那么在这个for循环的循环体中
就是用前两项之和
求得当前下标为i的这一项
每次做完循环以后
这个循环控制变量
也就是数组的下标要增1
求完了数列前20项的和
放到数组里面以后呢
接下来我们就要输出数组
同样适合用循环来输出
依次处理数组的各个元素
那么这里呢
我们希望输出结果呢
每五个一换行
所以在for循环中
配合了一个if选择结构
当i除以5余数为0的时候
就输出一个换行
另外我们设置
每一项的输出宽度为12
这样的话就对得比较整齐
最后输出每一个f[i]
就是数组的元素
也就是
这个Fibonacci数列的各个项
-导学
--第1章导学
-计算机系统简介
--计算机系统简介
--计算机系统简介 测试题
-计算机语言和程序设计方法的发展
--计算机语言和程序设计方法的发展 测试题
-面向对象的基本概念
--面向对象的基本概念 测试题
-程序的开发过程
--程序的开发过程
--程序的开发过程 测试题
-信息的表示和储存
--计算机的数字系统
--数据的编码表示
--信息的表示和储存 测试题
-实验指导
-导学
--第二章导学
-C++语言概述
--C++语言概述 测试题
-基本数据类型、常量、变量
--程序举例
--基本数据类型、常量、变量 测试题
-运算与表达式
--运算与表达式 测试题
-实验二:简单程序设计(上)
-数据的输入和输出
--数据的输入和输出
--数据的输入和输出 测试题
-选择结构
--if语句
--switch语句
--选择结构 测试题
-循环结构
--for语句
--循环结构 测试题
-自定义类型
--自定义类型
--自定义类型
-第2章小结
--第二章小结
-实验二:C++简单程序设计(下)
-导学
--导学
-函数定义
--函数定义
--函数定义 测试题
-函数调用
--例3-2
--例3-3
--例3-4
--例3-5
--例3-6
--函数调用 测试题
-嵌套与递归
--例3-9
--例3-10
--嵌套与递归 测试题
-函数的参数传递
--函数的参数传递
--函数的参数传递 测试题
-引用类型
--引用类型 测试题
-含有可变参数的函数
--含有可变参数的函数 测试题
-内联函数
--内联函数 测试题
-constexpr函数
--CONSTEXPR函数课后习题
-带默认参数值的函数
--带默认参数值的函数 测试题
-函数重载
--函数重载 测试题
-C++系统函数
--C++系统函数习题
-第3章小结
--第三章小结
-实验三(上)函数的应用
-实验三(下)函数的应用
-导学
--导学
-面向对象程序的基本特点
--面向对象程序的基本特点 测试题
-类和对象
--类和对象的定义
--类和对象 测试题
-构造函数
--构造函数基本概念
--委托构造函数
--复制构造函数
--构造函数 测试题
-析构函数
--析构函数
--析构函数 测试题
-类的组合
--类的组合
--类的组合程序举例
--前向引用声明
--类的组合 测试题
-UML简介
--UML简介
--UML简介课后习题
-结构体与联合体
--结构体与联合体 测试题
-枚举类
--枚举类
--枚举类 测试题
-第4章小结
--第四章小结
-实验四(上)
--实验四(上)
-实验四(下)
--实验四(下)
-导学
--导学
-标识符的作用域与可见性
--标识符的作用域与可见性 测试题
-对象的生存期
--对象的生存期
--对象的生存期 测试题
-类的静态成员
--类的静态成员 测试题
-类的友元
--类的友元 测试题
-共享数据的保护
--共享数据的保护 测试题
-多文件结构和预编译命令
--多文件结构和预编译命令 测试题
-第5章小结
--小结
-实验五
--实验五
-导学
--导学
-数组的定义与初始化
--数组的定义与使用
--一维数组应用举例
--数组的定义与初始化 测试题
-数组作为函数的参数
--数组作为函数的参数 测试题
-对象数组
--对象数组
--对象数组 测试题
-基于范围的for循环
-指针的定义和运算
--指针的定义和运算 测试题
-综合实例
--综合实例
-实验六(上)
--实验六上
-指针与数组
--指针数组
--指针与数组 测试题
-指针与函数
--指针类型的函数
--指向函数的指针
--指针与函数 测试题
-对象指针
--对象指针
--对象指针 测试题
-动态内存分配
--动态内存分配 测试题
-智能指针
--智能指针
-vector对象
--vector对象
--vector对象 测试题
-对象复制与移动
--移动构造
--对象复制与移动 测试题
-字符串
--C风格字符串
--string类
--字符串 测试题
-第6章小结
--第六章小结
-综合实例
--综合实例
-实验六(下)
--实验六(下)