c++中的复合类型(数组,字符串,结构体,共用体,枚举)
本文为本人阅读c++ primer plus第4章复合类型做的小笔记,只是记录本人不熟悉或者容易出错的地方
数组
声明数组:typeName arrayName[arraySize]
- arraySize必须是整性常数或者const值,也可以是常量表达式,所有的值在编译的时候都是已知的,不可以是变量
sizeof运算符返回类型或者数据对象的长度
- 如果用于数组名如sizeof foobar,得到的是整个数组的字节数
- 如果用于数组元素如sizeof foobar[0],得到的是数组元素的大小
- 因此可以通过
sizeof foobar / sizeof foobar[0]
得到未知数组的长度
初始化原则:
- 如果只对数组一部分初始化,那么编译器会将其它元素设置为0(如
float a[5] = {2.0, 5.0}
);因此对数组的所有元素都初始化为0十分简单,只需要显式将第一个元素初始化为0即可
- 如果只对数组一部分初始化,那么编译器会将其它元素设置为0(如
c++11的数组初始化方法
- 初始化数组可以省略
=
:int a[2] {1, 2}
- 大括号可以没有东西,表示这些元素全都设置为0:
int a[5]{}
- 初始化数组可以省略
字符串
c++处理字符串的方法
- c风格
- 基于string
c风格
以空字符结尾,写为
\0
,ASCII码为0,用来标记字符串的结尾。- 这是易错点之一:例如,如果想储存并打印一个长度为n的字符串,那么char数组至少为n+1,最后一位需要置为
\0
,否则打印过程中,会一直将内存中随后的各个字节解释为字符并打印,知道遇到\0
为止
- 这是易错点之一:例如,如果想储存并打印一个长度为n的字符串,那么char数组至少为n+1,最后一位需要置为
字符串常量: 会隐式地包括
\0
,当然这是在数组长度足够的情况下char foobar[6] = "test"; // 实际为{'t', 'e', 's', 't', '\0', '\0'} char foobar[] = "test";
不可以将字符串常量(双引号)和字符常量(单引号)互换,如char a = “s”, 因为”S”实际表示的是字符串所在的内存地址,相当于将一个内存地址赋给a
- 字符串长度: strlen(), 需引入头文件sctring,返回的是储存在数组中的字符串长度,不是数组本身长度,也不包括
\0
c风格字符串输入
例子
char name[30]; cin >> name[30];
- cin判断已经完成字符串输入:空白(空格,制表符,换行符);因此上面的程序输如
Zhang Yi
时可能会出现问题 - iostream中的类如cin提供了面向行的输入的成员函数:getline()和get()
getline()
- 参数:
getline(char[] str, int length)
,同理,如果length为n,那么函数最多读取19个字符,余下空间添加\0
- 每一次读取一行,通过换行符来确定行尾,但是不保存换行符(储存在字符串时将换行符换为
\0
) - 运用例子:
cin.getline
get()
同getline类似,接收的参数相同,解释参数方式也相同,也读到行尾,但是并不再读取并丢弃换行符,而是让它留在输入队列中,故若不借助任何帮助,get是不能跨过换行符的,因为只要换行符存在,用多少次get函数都认为没有任何内容读取,但换行符任在输入队列中
cin.get(name, ArSize); cin.get(name, ArSize); // a problem
使用不带任何参数的cin.get()可以读取下一个字符(即使是换行符),故可以使用它来处理换行符
cin.get(name, ArSize); cin.get(); cin.get(name, ArSize); cin.get();
简化:由于
cin.get()
返回cin对象,故可以简化为cin.get(name, ArSize).get(); cin.get(name, ArSize).get();
关于读取字符串还可能会有各种问题,将在书本后面专门讲述
混合输入字符串和数字
问题例子
cin >> year; cin.getline(address, 80);
- 问题:用户根本没有输入地址的机会
原因:
- cin读取年份,将回车键生成的换行符留在输入队列
- cin.getline()看到换行符,认为是空行,将空字符串赋给address数组
解决:处理掉回车键产生的换行符
cin >> year; cin.get(); cin.getline(address, 80);
基于string
- 基本用法类似于c风格的char数组,变化不大
读取一行
string str; getline(cin, str);
读取一行的函数getline不同于读取c风格的cin.getline
- 没有使用句点表示法,说明getline()不是类方法
- 将cin作为参数,指出到哪里查找输入
- 没有指定str的长度,因为string对象根据字符串长度自动调整自己的大小
结构
声明
struct person { char name[30]; int age; }; // 别忘了分号表示声明结束
- 创建:
person child;
; 创建并初始化:
person child = { "Tom", 2 };
访问成员:句点。
child.name
c++11结构初始化
- 等号省略
- 空
{}
- 不允许缩窄类型
共用体
union,可以储存不同的数据结构,但是只能同时储存一种类型,即结构可以同时储存int,long,double,共用体只能储存int或者long或者double;union和struct结构相似,含义不同
union one4all { int int_val; double double_val; long long_val; };
例子
one4all pail; pail.int_val = 15; cout << pail.int_val; pail.double_val = 1.23; cout << pail.double_val; cout << pail.int_val << endl; // a problem
- pail有时可以是int变量,有时可以为double变量,union的长度为其最大成员的长度
枚举
定义:
enum color{red, green, yellow}
- color变为新类型,称为枚举(enumeration)
- red, green, yellow作为符号常量,依次对应数值0-2,称为枚举量
声明变量:
color light;
赋值:在不进行强制类型转换的情况下,只可以将定义枚举时使用的枚举量赋给这种枚举的变量
light = red; // ok light = 2000; // invalid
- 对于枚举,只定义了赋值运算符,没有定义算术运算
枚举量是整形,可以被提升为int类型,但是int类型不可以自动转换为枚举类型,但是可以强制转换(int 的值有效)
int crayon = red; // valid, color type promoted to int light = 3; // invalid, int not converted to color light = 1 + red; // valid light = red + green; // invalid, no '+' operation for enumeration. Werid !!! light = color(2);
设置枚举量的值:
enum { zero, null = 0, one = 1, numero_uno = 1}
,可以看出- 可以使用赋值运算符显式设置枚举量(必须为整数)
- 可以选择只对部分枚举量进行显式赋值
- 可以创建多个多个值相同的枚举量