督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正。

c和c++的数组和指针都属于低级的复合数据类型,比如c++的数组,类似vector容器,指针类似迭代器。低级的数据类型优势是速度快。但是容易出错,不好调试。现代c++程序,应该避免使用。

内置数据类型—数组,不方便存储变长数据,定义之后长度固定(静态数组),数组类似容器,比如,无法事先知道一个给定数组的长度,也没有类似size函数来求数组长度,也没有push_back()函数来添加元素,如果要更改数组长度,程序员只能重新建立数组,把旧的复制到新的。

记住现代c++程序,应该尽量是vector容器来替代数组,来存取同一类型的数据元素,只有当要求速度的前提下,如果使用容器不达标,那么再使用数组。

问题1、array由一系列的类型相同的元素构成,数组声明包括数组元素个数和类型,数组最好定义之后就初始化。

数组的声明

    //[]方括号表示声明的是数组,里面的数字表明了数组包含的元素数目
int states[];//声明50个整数的数组
double code[];//声明365个浮点数的数组
char chr[];//声明20个字符的数组

访问数组内容可以用下标表示单个元素,下标数字也叫索引(index),从0开始计算。

数组的初始化

    //用花括号括起来,元素用逗号隔开
int pow[] = {, , , , , , , };//只有标准c,c++支持此初始化语法
//pow[0]首元素赋值为1,以此类推

注意:数组声明的时候最好是初始化,虽然不会报错,但是和普通变量一样,使用没有初始化的数组,里面元素的值不定,出现垃圾值。

数组初始化列表和大小不一致的情况

初始化列表里的元素个数和数组大小不一致,当初始化元素数目少于数组大小,多余的元素自动初始化为0。如果没有初始化数组,那么和普通变量一样,存取的内存原来就有的垃圾值。初始化了,只不过部分初始化,那么编译器会自动初始化余下的元素为0。初始化了,但是初始化列表元素大于数组大小,那么编译出报错。

    //初始化没有完全,编译器自动后面给初始化为0
double d[] = {};//不过vs2010里编译运行,全都是0 //error C2078: 初始值设定项太多
double d[] = {, , , , , };

数组初始化小技巧

省略填写数组大小,让编译器自动的去判断数组的实际大小和初始化列表里的项目

    //空的方括号告诉编译器去初始化列表里判断数组实际大小
char chr[] = {'a', 'b', ' ', ''};
//这里需要一个技巧,人工判断数组大小容易出错,使用sizeof运算符计算
for (int i = ; i < sizeof(chr) / sizeof(chr[]); i++)
{
cout << "i + 1 = " << chr[i] << endl;
}

注意技巧:sizeof(数组名)求的是数组总共多大(字节单位),sizeof(数组【0】)求的是数组中一个元素的大小(字节单位),两者除法,就是数组的实际大小(元素个数)。

数组使用小技巧(常量大小)

    const int NUM = ;//常量代表数组大小,推荐的技巧
int days[NUM] = {, , , };//良好的编程风格,如果以后想修改数组大小,只需要修改开头的常量即可 for (int index = ; index < NUM; index++)
{
cout << days[index] << endl;
}

对数组指定元素初始化

属于C99的新特性,可以对数组指定的元素直接初始化,如果对数组最后一个元素初始化,那么传统语法必须顺次初始化到最后一个元素前,才能对最后一个元素初始化。

    //对最后一个元素初始化为1
float f[] = {, , };

而c99规定可以直接去初始化

    //使用方括号【】,直接对数组某个元素初始化
int i[] = {i[] = };//ok!需要加 数组名【】
//int in[5] = {[4] = 10};//error C2059: 语法错误:“[”

对于一般的数组初始化,部分初始化之后,余下的自动初始化为0(这里vs2010编译器不是这样的,全部都是0 了),如果在指定的初始化元素后还有别的初始化值,那么这些数值自动对数组后续元素进行初始化,并且指定初始化元素的数值在第几个元素处,那么也会同样初始化这个元素。

比如in【0】=11在第5(0-5)个元素位置,那么同时打印第5个元素=11。说明初始化指定元素的同时,也用这个数值初始化本位置的元素了。

如果多次对数组某个元素初始化,则最后一次为准。

    int in[] = {, , in[] = , , , in[] = };   //首元素i0=11,i5=11
int i; for (i = ; i < ; i++)
{
cout << "i" << i << " = " << in[i] << endl;
}

只读数组

如果只需要对数组读取,而不进行修改,那么推荐关键字const

const int days[NUM] = {, , , };//数组中每个元素都当作常量处理,和普通变量一样,const数组也需要声明的时候初始化

数组的赋值

使用数组下标(索引)为数组元素赋值,c和c++不支持整体赋值的初始化,或者就是单纯的赋值,也不支持用花括号括起来的列表进行赋值(初始化除外)

    double d[SIZE] = {, , };//ok这是可以的,列表进行初始化
int i[SIZE]; for (int count = ; count < SIZE; count++)
{
i[count] = * count;//ok,使用循环和数组下标给数组元素赋偶数值
} //i = d;//error,c不支持数组整体赋值
//i[SIZE] = d[SIZE];//error //d[SIZE] = {11, 22, 33};//不起作用,这种形式只有初始化可以使用,赋值必须使用索引

数组的边界问题

千万不要越界(类似数据类型的越界),数组索引不能越界,因为编译器不会检测这种错误。编译器不会检测索引的合法性,如果出现非法的索引,那么结果未知,有时候会中断,但是也有时候可以执行,但是结果很奇怪(编译器不同而不同),编译器不检测数组边界,是出于信任程序员,可以节省时间和效率。

注意:记住,数组计数原则上都从0开始,并且数组大小用符号常量代替。减少错误的发生。

再看数组大小的指定

前面可以用整型常量(unsigned)或者字符常量来指定大小,C99之前就是这两种方法。

    const int const_m = ;//在c语言(不同于c++)里,const值不被看作是常量,在c++里,这样的定义的变量,也就是const常量,可以去做数组的维数。
int n = ;//定义了变量n double d1[];// ok
double d2[ * + ];//ok
double d3[];//error,没有初始化,也没有大小指定
double d4[sizeof(int)];//ok,sizeof表达式在c里被认为返回一个整数常量
double d5[-];//error C2118: 负下标
double d6[];//error C2466: 不能分配常量大小为 0 的数组
double d7[3.14];// error C2058: 常量表达式不是整型
double d8[(int)3.14];//ok double d9[const_m];// error C2057: 应输入常量表达式,“d9”未知的大小,不能分配常量大小为 0 的数组
double d10[n];//error C2057: 应输入常量表达式,“d9”未知的大小,不能分配常量大小为 0 的数组

c99之后,后两种方式可以了,并且创建了一种新数组VLA(variable length array)变长数组,VLA。目的是为了让c更适合做数值计算。

问题2、下列语法是不合法的

int ia[get_size()];

非法,get_size()是函数调用,不是常量表达式,不能用于定义数组的维数(维长度)。记住,必须是程序编译期间就得确定数组的大小,运行期间的不行。

问题3、注意下列数组的初始值

//ia 为在函数体外定义的内置数组,也就是全局变量,各元素初始化为0
int ia[];
//sa为元素类型为string 的数组,自动调用string 类的默认构造函数将各元素初始化为空字符串
string sa[]; int main(void)
{
//sa2 为元素类型为string 的数组,自动调用string 类的默认构造函数将各元素初始化为空字符串
string sa2[]; //ia2 为在函数体内定义的内置数组,各元素未初始化,其值不确定
int ia2[]; system("pause");
return ;
}

问题4、不要把数组和vector容器混淆

    //vector 对象不能用这种方式进行初始化。
//vector<int> ivec = {0, 1, 1, 2, 3, 5, 8};
    int ia3[] = ivec;//错误。不能用vector 对象来初始化数组。

定义数组时可使用初始化列表来初始化数组的部分或全部元素。如果是初始化全部元素,可以省略定义数组时方括号中给出的数组维数值。

如果指定了数组维数,则初始化列表提供的元素个数不能超过维数值。如果数组维数大于列出的元素初值个数,则只初始化前面的数组元素,剩下的其他元素,若是内置类型则初始化为0,若是类类型则调用该类的默认构造函数进行初始化。

字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。

问题5、列出使用数组而不是vector 的缺点

与vector 类型相比,数组具有如下缺点:数组的长度是固定的(C99之前),而且数组不提供获取其容量大小的size 操作,也不提供自动添加元素的push_back 操作。因此,程序员无法在程序运行时知道一个给定数组的长度,而且如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组的存储空间中去。与使用vector 类型的程序相比,使用内置数组的程序更容易出错且难以调试。

问题6、注意数组下标越界问题

类似vector容器,string类型,别无他法,一定自习检查。常见的“缓冲区溢出错误”,就是在编写代码的时候,引用了越界的下标,没有检查下标的范围,导致出错!

欢迎关注

dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

把《c++ primer》读薄(4-1 c和c++数组)的更多相关文章

  1. C++ Primer 第3章 字符串、向量和数组

    C++ Primer 第3章 字符串.向量和数组 C Primer 第3章 字符串向量和数组 1 命名空间的using声明 2 标准库类型string 3 标准库类型vector 4 迭代器介绍 5 ...

  2. C Primer Plus学习笔记(九)- 数组和指针

    数组 数组由数据类型相同的同一系列元素组成 需要使用数组时,通过声明数组告诉编译器数组中内含多少元素和这些元素的类型 普通变量可以使用的类型,数组元素都可以用 float candy[365]; // ...

  3. 【原创】一起学C++ 之指针、数组、指针算术 ---------C++ primer plus(第6版)

    C++ Primer Plus 第6版 指针和数组基本等价的原因在于指针算术! 一.指针 ⑴整数变量+1后,其值将增加1: ⑵指针变量+1后,增加的量等于它指向的类型的字节数: ⑶C++将数组名解析为 ...

  4. C++ Primer 笔记——数组

    1.数组的大小是固定不变的,声明时必须指定大小(或者使用列表初始化),而且大小必须大于0,C++ Primer里面也建议,如果不确定元素的个数,请使用vector. ]; , , }; //数组长度固 ...

  5. c++引用和const 用法 数组 指针

    非const引用,只能用object为其赋值: <c++primer>P52 而const引用则可以用临时变量为其赋值: 如: const int &r = 32://可以 int ...

  6. 把《c++ primer》读薄(1-2前言+变量和基本类型)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 一:大小端的概念 Big-Endian和Little-Endian(见计算机存储的大小端模式解析) 二:浮点数的机器级表示 (见 ...

  7. 把《c++ primer》读薄(4-2 c和c++的数组 和 指针初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 问题1.我们知道,将一个数组赋给另一个数组,就是将一个数组的元素逐个赋值给另一数组的对应元素,相应的,将一个vector 赋给另 ...

  8. 把《c++ primer》读薄(3-3 标准库bitset类型)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. //开头 #include <bitset> using std::bitset; 问题1.标准库bitset类型( ...

  9. 把《c++ primer》读薄(3-2 标准库vector容器+迭代器初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 标准库vector类型初探,同一种类型的对象的集合(类似数组),是一个类模版而不是数据类型,学名容器,负责管理 和 存储的元素 ...

随机推荐

  1. GitHub for Windows 內建 Git Shell 執行時顏色所代表的意義

    在使用指令列版控的過程中,經常有機會用到 Git Shell 這套優異的 Git 版控環境,一來他使用 Windows PowerShell 為核心,其訊息顯示與輸入都支援 Unicode,比較不會有 ...

  2. HDU--跑道相遇

    跑道相遇 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submis ...

  3. 有哪些LabVIEW快捷键让你相见恨晚

    前言 任何一门工具,当你使用它到极致的时候,往往都朝着这样子的两个方向发展 1. 具有鼠标操作功能的软件,他的使用的极致就是脱离鼠标,迈向键盘 2. 主要是键盘操作的,他的极致就是脚本自动化,或者说一 ...

  4. Shell下突破安全狗远程桌面守护

    首先在Shell下把安全狗的安装配置给下来 默认安装路径: C:\Program Files\SafedogServer\SafeDogGuardCenter  找到 ProGuardData.ini ...

  5. TreeView 使用方法:(在View.Details模式下)

    1.建立TreeView的標題         2.建立TreeView的Item         3.在TreeView的Item中的建立SubItem                  如果將各部 ...

  6. 用C#语言在Visual Studio 2010里开发一个自定义的PowerShell Cmdlet

    1. 打开Visual Studio 2010 2. 新建一个基于Class Library的项目 3. 给项目起个名字然后OK 4. 为项目添加下列Reference System.Manageme ...

  7. International Conference for Smart Health 2015 Call for Papers

    Advancing Informatics for healthcare and healthcare applications has become an international researc ...

  8. C#动态编译引擎-CS-Script

    什么是CS-Script? CS-Script是一种以CLR(公共语言运行库)为基础的脚本系统,它使用ECMA标准的C#作为编程语言,它面向微软的CLR运行库(.net 2.0/3.0/3.5/4.0 ...

  9. [ASP.NET MVC 小牛之路]17 - 捆绑(Bundle)

    本文介绍 MVC 4 提供的一个新特性:捆绑(Bundle),一个在  View 和 Layout 中用于组织优化浏览器请求的 CSS 和 JavaScript 文件的技术. 本文目录 了解VS默认加 ...

  10. 【VC++技术杂谈005】如何与程控仪器通过GPIB接口进行通信

    在工控测试系统中,经常需要使用到各类程控仪器,这些程控仪器通常具有GPIB.LAN.USB等硬件接口,计算机通过这些接口能够与其通信,从而实现自动测量.数据采集.数据分析和数据处理等操作.本文主要介绍 ...