第4章 复合类型
目录
1、数组
typeName arrayName[arraySize];
- 存储相同类型的值。每个值都存储在一个独立的元素中,在内存中依次存储。
- 声明,arraySize不能是变量,变量是在程序运行时设置的。其值必须在编译时已知。
- 编译器不会检查下标是否有效,运行会异常。
- sizeof() 数组名,得到整个数组的字节数。
初始化
- 只有定义数组时才能初始化,也不能将一个数组赋值给另一个数组。
- 可以使用下标的方式对元素赋值。
- 如果只对一部分元素初始化,则编译器会将其他元素置为0。
- 只要显示地将第一个元素初始化为0,编译器会将其他元素都初始化为0。
- 大括号不含任何元素,将默认置为0。
- [] 为空,编译器会计算元素个数。
- 初始化可省略 = 。
long plifs[] = { 25, 92, 3.0}; //错误,将浮点数转为整型时缩窄操作
char slifs[4] = { 'h', 'i', 1122011, '\0' }; // 错误,超出char表示范围
char slifs[4] = {'h', 'i', 112, '\0'}; //正确,虽然112是int值,但在char变量的取值范围内0~255
- 列表初始化禁止缩窄转换。
2、字符串
字符数组
char dog[8] = {'d', 'o', 'g', '', 'd', 'o', 'g', 'd'}; //不是字符串
char cat[8] = {'c', 'a', 't', 'c', 'a', 't', 'c', '\0'}; //是字符串
- 字符串是存储在内存的连续字节中的一系列字符。
- 可以存储在char数组中。以空字符(null character)结尾。
- 空字符被写作 \0,其ASCII码为0(NULL),用来标记字符串结尾。
打印
- cout 打印字符串,会逐个处理字符串中的字符,直到遇到空字符为止。
- 如果定义的字符数组中间出现了 '\0' ,则后面的不打印。
- 如果定义的字符数组没有定义 '\0',则会继续打印后续内存中各个字节解释为要打印的字符,直到遇到空字符。(好在空字符很常见)
int variSize = 10;
char name[variSize] = "123450678"; // error: variable-sized object may not be initialized
cout << name;
const int size = 10;
char name[size] = "123450678";
cout << name << endl; // 123450678
char name2[size] = "123 45678";
cout << name2 <<endl; // 123 45678
char name1[size] = "123\045678";
cout << name1 <<endl; // 123%678
char arrName[size] = {'1', '2', '3', '4', '5', '\0', '6', '7', '\0'};
cout << arrName << endl; // 12345
字符串常量
char bird[11] = "Mr. Fan";
char fish[] = "Rice";
- 初始化采用双引号表示,隐式地包括结尾的空字符,不用显式声明。
- 应保证数组足够大,可以保存所有字符(包括结尾的空字符),因此需定义 [字符长度+1] 。
- 在确定存储字符串所需最短数组时,需要计算结尾空字符。[] 为空让编译器自动计算更为安全。
- C++对字符串长度没有限制。
- 数组比字符串长没有害处,只会占用空间。
字符串常量 与 字符常量 区别
- 字符串常量使用双引号,字符常量使用单引号,不能互换。
- 字符常量'S',是字符串编码的简写,在ASCII系统上,只是83的另一种写法。
- 字符串常量 "S",是 'S' + '\0' 组成的字符串。"S" 实际上表示的是字符串所在内存地址。
- 拼接时,任何两个由“空格、制表符、换行符”分隔的字符串常量都将自动拼接成一个,中间没有空格。
- 前一个字符串中的 '\0' 将被下一字符串的第一个字符取代。
sizeof 与 strlen
- sizeof 返回整个数组的长度:10字节。
- strlen 返回实际长度,指存储在数组中的字符串的长度,只计算可见字符,且不包含结尾的空字符 '\0' 。
- 注意:未初始化的字符数组包含的内容是随机的,即使定义了size,使用strlen()时,从第一个元素开始,遇到'\0'结束,返回的长度是随机的。
- strlen 是库函数,包含在头文件<cstring>中。
const int size = 10;
// char name[size] = "0123456789"; // error: initializer-string for char array is too long
char name[size] = "123";
char name2[size] = "1 2";
char arrname[size] {'1', '2', '3'};
char arrname1[size] {'1', '2', '3', '\0'};
char arrname2[size] {'1', '2', '3', '\0', '4'};
char arrname3[size] {'1', '2', '3', ' ', '4'};
cout << sizeof(name) << endl; // 10
cout << sizeof(name2) << endl; // 10
cout << sizeof(arrname) << endl; // 10
cout << sizeof(arrname1) << endl; // 10
cout << sizeof(arrname2) << endl; // 10
cout << sizeof(arrname3) << endl; // 10
cout << strlen(name) << endl; // 3
cout << strlen(name2) << endl; // 3
cout << strlen(arrname) << endl; // 3
cout << strlen(arrname1) << endl; // 3
cout << strlen(arrname2) << endl; // 3
cout << strlen(arrname3) << endl; // 5
字符串输入
// 输入内容小于容器
const int Size = 10;
char name[Size];
cin >> name; // fan
cout << sizeof(name) << endl; //10
cout << strlen(name) << endl; //3
// 输入内容大于容器
const int Size = 10;
char name[Size];
cin >> name; // 123456789101112
cout << sizeof(name) << endl; //10
cout << strlen(name) << endl; //15
- 将键盘输入读入到char数组中时,cin 将自动加上结尾的空字符。
const int Size = 10;
char name[Size];
cin >> name; // 12345678 9
cout << sizeof(name) << endl; //10
cout << strlen(name) << endl; //8
- cin :键盘无法输入空字符,cin将空白(空格、制表符、换行符)作为字符串结束位置,自动在空白处填入结束符放入数组,每次只能读取一个单词。
- 不会读取换行符,将其留在输入队列中
getline() 和 get()
- 面向行的输入,通过回车键输入的换行符来决定输入结束。
- cin.getline(para, size) :每次读取一行,读取到指定字符数或读取到换行符停止。将换行符读取到数组中,并用空字符替换。
- cin.getline(para, size) 最多读取size-1个字符,自动在结尾添加空字符。
- cin.get(para, size) :每次读取一行,不会读取换行符。
- 如果连续调用cin.get();由于第一次调用会遗留换行符在队列中,导致第二个get读取的第一个参数就是换行符,不再get后续参数。
- 不带参数的cin.get() : 可以读取下一个字符,即使是换行符。
- 通过添加无参的读取换行符,为读取下一行做准备。
区别:
- getline()简单,get()检查错误更细。通过使用get()读取,可以通过下一个字符是否为换行符判断,是换行符表示已读取了整行,不是换行符说明已读取到指定长度字符,还有其他输入。
- 读取到空行时,get()会设置失效位。
- 输入字符长度大于分配内存时,均会保留剩余字符在输入队列中,getline()会设置失效位。
- 失效位需要通过 cin.clear(); 恢复输入
例
- cin(); cin.getline(); cin.get() 返回对象,通过对象调用无参数的 cin.get(); 跳过换行符。
// 单独调用
int year;
cin >> year; // 会留下换行符
cin.get(); // 读取换行符
cin >> month; // 再进行读取
// 拼接对象调用
(cin >> year ).get();
3、string 类
- string 类位于命名空间std中。
- 程序可以自动调整string的大小。
- char数组存储字符串的存储单元,string类变量时表示字符串的实体。
- 未被初始化的string对象的长度被自动设置为0 。
- 可以用string对象给string对象赋值。
初始化
拼接
// 字符串类直接+
str1 = str2 + str3;
输入
cin.getline(chrr, 20); // .getline是istream类的类方法
cin.getline(cin, str); // getline不是
void test_str(){
string str1 = "string";
char chr[10] = "string";
cout << str1.size() << endl;
cout << strlen(chr) << endl; //strlen只接受char数组
}
4、结构struct
- 结构可以存储多种类型的数据。定义新类型后,便可以创建对应的变量。用关键字struct声明。注意结尾;
- 用成员运算符(.)访问各个成员。
struct inflatable
{
char name[20];
float volume;
double price;
};
inlatable hat;
hat.name = "rice";
- 结构声明的位置很重要,外部声明可以被后面的任何函数使用。
- C++不提倡使用外部变量,支持外部声明符号常量。
初始化
- 结构初始化可以放在同一行中 inflatable duck { "Daphne", 0.12, 9.98};
- 括号中无内容,各成员将被置为0 。不允许缩窄。
struct perks
{
int key_number;
char car[12];
} mr_smith, mr_jones;
inflatable gifts[100];
inflatable guests[2] =
{
{"rice", 0.1, 1.32},
{"fan", 0.2, 2.32}
};
5、共用体 union
- 存储不同数据类型,但只能同时存一种。
- 共用体用处:当数据项使用两种或多种格式,但不会同时使用时,可节省空间。
- 共用体长度为其最大成员的长度。
union one4all
{
int int_val;
long long_val;
double double_val;
} one, two;
6、枚举 enum
- enum 提供了另一种创建符号常量的方式,可以代替const。
- 枚举值定义了赋值运算,没有算术运算,所以最常用来定义符号常量。
- 显式声明可以创建多个值相同的枚举量。
- 只有声明中指出的值是有效的,bs取值只有3个有效值。除非强制类型转换:bs = bigstep(4); 4 不是枚举值,但在取值范围内。
- 枚举值的取值范围:上限:由于third=101,大于且最接近此值的2的幂次值为128,则上限范围为127。下限同理:若不小于0,下限为0,否则,例最小枚举量为-6,2的幂次8最接近,则取值范围的下限为-8。