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

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. Python之路【第六篇】python基础 之面向对象进阶

    一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象  和  issubclass(su ...

  2. python Django session/cookie

    一, Cookie #cookie # def cook1(request): # print(request.COOKIES) # 查看cooke # # print(request.get_sig ...

  3. jQuery中事件与动画的总结

       1.加载DOM     1.1.window事件 window.onload=function(){}.... 时机:其他资源都加载完毕后,再执行   $(function(){}) ……:只是 ...

  4. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  5. perl 遍历对象数组

    my $appsList ; eval { $appsList = $db->query( $sqlstr1 )->hashes->to_array; }; ### $appsLis ...

  6. 剑指Offer面试题:28.连续子数组的最大和

    一.题目:连续子数组的最大和 题目:输入一个整型数组,数组里有正数也有负数.数组中一个或连续的多个整数组成一个子数组.求所有子数组的和的最大值.要求时间复杂度为O(n).例如输入的数组为{1,-2,3 ...

  7. 前端编码规范之CSS

    "字是门面书是屋",我们不会去手写代码,但是敲出来的代码要好看.有条理,这还必须得有一点约束~ 团队开发中,每个人的编码风格都不尽相同,有时候可能存在很大的差异,为了便于压缩组件对 ...

  8. [.net 面向对象程序设计进阶] (26) 团队开发利器(五)分布式版本控制系统Git——图形化Git客户端工具TortoiseGit

    [.net 面向对象程序设计进阶] (26) 团队开发利器(五)分布式版本控制系统Git——图形化Git客户端工具TortoiseGit 读前必备: 接上篇: 分布式版本控制系统Git——使用GitS ...

  9. 64位Win7添加32位XP的共享打印机

    windows无法连接到打印机 错误提示0x00000214 win7 64位系统,连接32位xp上的共享打印机,提示“操作失败,错误为 0x00000214”. 使用以下方法连接就没问题了: 开始— ...

  10. 谈初学Java历程

    学习Java一个月左右,本来很早就想好好静下心来写一点东西了.但由于不想手写,文档写了不知道放在哪好,所以一直拖着.最近注册了博客园,还是挺方便的. 即将大学毕业了,则面临了所以大学生所面临的问题,就 ...