C++常用数据结构
1.数组
-
数组(array)是一种数据格式,能够存储多个同类型的值。
-
数组声明方法:
typeName arrayName[arraySize](arraySize必须是整数)
例如:short months[12],其含义指创建了一个名为months的short类型的数组,数组内有12个元素。其中,数组months中的每一个元素,都可以单独访问。如:months[0]、months[1]、……、months[11]可以一一访问数组中的元素。(C++数组中从0开始编号)
数组初始化规则
- 数组初始化只有在声明数组时使用,也不可以将一个数组赋给另一个数组。
int cards[4] = {3,6,8,10}; //正确初始化数组
int hard[4];
hard[4] = {3,6,8,10}; //错误使用
hard[4] = cards[4]; //错误使用
- 初始化数组时,可以提供少于数组arraySize的元素数目。
float hotelTips[5] = {5.0,2,5}; //指数组中第一、第二个元素值为5.0、2.5,其余元素为0
- 初始化数组时,[ ]中的arraySize可以为空,C++编译器能自动计算元素个数
short things[] = {1,5,3,8}; //指数组things含有4个元素
这种初始化方法容易丢失元素,最好输入arraySize
- C++数组初始化的方法
- 可以省去
= {}可以不包含元素,意为所有元素为0- 初始化时,禁止缩窄转换,即浮点数不可以转换为整型
2.字符串
-
字符串是存储在内存的连续字节中的一系列字符。(C++有两字符串处理方式:C-style string和string类)
-
将数组初识化为字符串有两种方式:
//第一种方法:
//C-style string以空字符结尾(null character),被写作\0,ASCII码为0,不以空字符结尾的不是字符串
char dog[5] = {'b','e','u','a','e'}; //没有以空字符'\0'结尾,不是字符串
char cat[5] = {'b','e','u','a','\0'}; // 是字符串
//第二种方法:
char bird[11] = "Mr. Cheeps";
//其中,11个元素包含空字符,若arraySize大于元素数目,则其余未输入字符算作空字符'\0'
常用第二种方法来将数组初始化为字符串。字符串常量用双引号,字符常量用单引号,不能互换。
char shirt_size = 'S'; //指将S的ASCII值83赋给shirt_size
//"S"不是字符常量,是字符串常量,表示两个字符(字符S和\0)
char shirt_size = "S" //这是错误的表达方式
字符串常量拼接
当字符串很长时,可以将两个引号括起的字符串合并成一个。
//下面两个语句时等效的,且第一个字符串中的空字符\0,会被第二个字符串的第一个字符取代
cout << "I'd give my right arm to be" " a great violinist.\n";
cout << "I'd give my right ar"
"m to be a great violinist.\n";
字符串输入
两次输入字符串产生的问题:
#include <iostream>
int main()
{
using namespace std;
const int ArSize = 20;
char name[ArSize];
cahr dessert[ArSize];
cout << "Enter your name:\n";
cin >> name;
cout << "Enter your favorite dessert:\n";
cin >> dessert;
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
return 0;
}
//运行结果为:
Enter your name:
Alistair Dreeb
Enter your favorite dessert:
I have some delicious Dreeb for you, Alistair.
上述代码中,在第一次cin >> name后,程序便显示结果,并立即显示最后一行。这是因为,cin使用空白(空格、制表符和换行符)来确定字符串的结束位置,所以cin在获取字符串数组时只读取一个单词并自动在结尾添加空字符。第二次cin >> dessert时,程序发现输入的第二个单词Dreeb,便读取了它。
解决方法: 使用getline()或get()函数
- getline()通过回车键(Enter)输入的换行符来确定结尾。调用方式:
cin.getline(arrayName,arraySize)
char name[10];
cout << "Enter your name: ";
cin.getline(name,10); //其中,10个元素包含空字符\0,故最多输入9个字符
- get()与getline()的调用方式类似,但get()不再读取并丢失换行符,而是将其保留在输入队列中。故两次使用时,会导致第二次读取的第一个字符时换行符,而没有任何可读取的内容。
cin.get(name,ArSize); //第一次读取正常
cin.get(dessert,ArSize); //第二次读取错误,无可读取内容
//可通过下述方法解决
cin.get(name,ArSize);
cin.get();
cin.get(dessert,ArSize);
或者
cin.get(name,ArSize).get(); //即有多次cin输入时,在结尾继续调用一个get()
cin.get(dessert,ArSize);
输入数字和字符串产生的问题:
#include <iostream>
int main()
{
using namespace std;
cout << "What year was your house built?\n";
int year;
cin >> year;
cout << "What is its street address?\n";
chat address[80];
cin.getline(address,80);
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
//运行结果
What year was your house built?
1966
What is its street address?
Year built: 1966
Adress
Done!
上述代码中,地址(address)根本没输入机会,程序便运行完了。这是因为,cin读取年份时,将回车键生成的换行符留在了输入队列。故后面的cin.get(address,80)首先读取到换行符。
解决方法:
cin >> year;
cin.get();
或者
(cin >> year).get();
字符串中用到的函数
- strlen函数
strlen函数可以返回存储在数组中的字符串的长度,并非数组长度。strlen函数只计算可见字符,不把空字符计算在内。因为strlen()函数是C语言库函数中的,所以使用前要包含标准头文件cstring
char name[5] = "abcd";
cout << "Your name has " << strlen(name) << " letters.\n"
// 输出结果是Your name has 4 letters.
// arraySize = strlen(array) + 1
3.String类
- string类使用前,必须在程序中包含头文件string,并string类位于名称空间std中,所以要提供一条using编译指令(或者std::string)。
- string对象和字符数组主要区别是可以将string对象声明为简单变量,而不是数组
string str1; //创建一个string对象或者说string类型的变量
string str2 = "panther"; //初始化字符串
字符串初始化、赋值、拼接和附加
- 字符串初始化
string first_date = {"The Bread Bowl"};
string second_date = {"Hank's Fine Eats"};
//string类型的变量不用加[]
- 赋值
不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象
char char1[20];
char char2[20] = "jaguar";
string str1;
strign str2 = "panther";
char1 = char2; //错误使用
str1 = str2; //正确使用
- 拼接和附加
string str3;
str3 = str1 + str2;
str1 += str2; //等效于str1 = str1 + str2
字符串中常用函数
- strcpy()函数
strcpy函数可以将字符串复制到字符数组中。
strcpy(charr1,charr2); //将charr2中字符串复制到charr1中
- strcat()函数
strcat()函数将字符串附加到字符数组末尾。(concatenate,连接)
strcat(charr1,charr2); //将charr2附加到charr1末尾
- strncpy()和strncat()函数
当使用strcpy()和strcat()后,有可能原数组内存不够,导致覆盖相邻的内存,从而引起程序终止或者数据被破坏。而strncpy()和strncat()能自动调整大小。
- size()函数
string str = "abcde";
int len1 = str.size(); //意为将str对象的字符数赋给len1
字符串输入
将一行输入读取到数组中的代码:
cin.getline(charr,20);
将一行输入读取到string对象中的代码:
getline(cin,str);
在string对象中未使用句点表示法,说明getline()不是类方法。以cin为参数,指出到哪里去查找输入,并且未指出字符串长度参数,是因为string对象能更具字符串的长度自动调整大小。
原始字符串
原始(Raw)字符串中,字符表示的就是自己,即没有转义序列一说法。例如:\n不表示换行符,表示两个常规字符——斜杠和n,因此可以显现出来。原始字符串将“(和)”用作定界符,并用前缀R来标识原始字符串。
cout << R"(Jim "King" Tutt uses "\n" instead of endl.)” << '\n';
//显示结果为Jim "King" Tutt uses "\n" instead of endl.
如果原始字符串中包含)”的话,可以在“和(中加入其他字符。
cout << R"+*("(Who wouldn't it?)", She whispered.)*+"" << endl;
4.结构
结构是一种能够存储多种数据类型的数据格式。定义结构方式:定义结构描述和描述创建结构变量。
struct inflatable
{
char name[20]; //结构中的成员,一条声明语句,注意冒号“;”
float volume;
double price;
}; //该过程是声明结构这一数据类型,故也是一条声明语句,结尾要加上";"
上述代码中,inflatable是标识符,意为含上述代码中数据格式的新类型。定义结构可以放在函数内部,也可以在外部定义。区别就是函数内部定义,该结构只能在该函数中使用;外部定义,则整个程序都可以使用。
定义完结构后,就可以创建这种类型的变量了。
inflatable hat;
inflatable woopie_cushion;
其中,hat和woopie_cushion的类型为infalatable,因此可以用成员运算符(.)来访问其中的成员。例如:hat.volume、hat.price、woopie_cushion.price等就是结构中的成员,其的访问成员与float、double等变量没有区别。
结构初始化
inflatable duck = //等于号可以省略
{
"Glorious Gloria", //因数据类型是字符串数组,故要用到双引号
1.88, //因不是语句,故结尾不用冒号,用顿号
29.99 //结构成员中数据类型的赋值,与常规的整型、浮点型复制没有区别
}; // 初始化的过程是一个语句,结尾要加上冒号
可以使用赋值运算符(=)将一个结构赋给另一个同类型的结构
infalable choice;
choice = duck; //上个程序中新类型duck
结构数组
标识符inflatable也可以包含一个数组,也就是可以创建元素为结构的数组。
inflatable gifts[2]; //创建了一个是新类型inflatable的gifts[2]数组
其中,gifts是一个Inflatable数组,内部的每一个元素(如gifts[0]、gifts[1]等)都是inflatable对象。
初识化结构数组:
inflatable gifts[2] =
{
{"Bambi",0.5,21.99},
{"Godzilla",2000,565.99}
};
上述代码中,可以使用gifts[0].volume、gifts[1].price来访问gifts数组元素中的元素。
结构中的位字段
结构中的位字段是指定占用特定位数的结构成员。字段类型为整型或枚举,接下来是冒号,冒号后面是一个数字,用来指定使用的位数。每个成员占有特定的位数,称为位字段。
struct torgle_register =
{
unsigned int SN : 4; //意为SN变量占4bits
unsigned int : 4; //使用没有名称的字段来提供间距
bool goodIn : 1;
bool goodTorgle : 1;
};
共用体
共用体(union)是一种数据格式,能够存储不同的数据类型,但只能同时存储其中的一种类型。例如:结构可以同时存储int、long和double,共用体只能存储int、long或double。用法与结构类似。
union one4all
{
int int_val;
long long_val;
double doubel_val;
};
//可以使用one4all变量来储存int、long或doubel,前提是在不同的时间使用
one4all pail;
pail.int_val = 15;
cout << pail.int_val;
pail.double_val = 1.38;
cout << pail.double_val;
因为共用体每次只能存储一个值,因此必须有足够的空间来存储最大的成员。
共用体的使用
当数据项使用两种或更多格式(但不会同时使用)时,可节省空间。例如:一些商品的ID为整数,而另一些为字符串时,可以进行下面的方法:
struct widget =
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val; //定义共用体的同时,创建了一个共用体类型的id_val变量
};
...
widget prize;
...
if (prize.type == 1)
cin >> prize.id_val.id_num;
else
cin >> prize.id_val.id_char;
匿名共用体没有名称,其成员将成为位于相同地址处的变量。
struct widget =
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}; //定义共用体的同时,创建了一个共用体类型的id_val变量
};
...
widget prize;
...
if (prize.type == 1)
cin >> prize.d_num;
else
cin >> prize.id_char;
//id_num和id_char被视为prize的两个成员,它们地址相同
5.枚举
C++的enum工具提供了另一种创建符号常量的方式,可以用来替代const。定义 枚举方式如下:
enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};
- spectrum被称为枚举(enumeration),是一种新类型(类似于int、long、double等类型),就像struct变量被称为结构一样。
- red、orange、yellow等作为符号常量,依次对应整数0~7,称为枚举量。(默认情况下第一个枚举量为0,第二个枚举量为1)
创建枚举变量
创建枚举变量
spectrum band; //创建一个spectrum类型的枚举变量
band = blue; //意为将bule对应的4赋给band
band = 2000; //错误,只能将定义枚举时的枚举常量赋给枚举变量,所以受spectrum影响band只有8个可能值
band = spectrum(3); //等同于将3赋给band,前提是()内的int值是在定义的枚举量中才行
对于枚举,只定义了赋值运算符,没有算术运算符
band = orange; //正确
++band; //错误
band = orange + red; //错误
而且,枚举量是整型,可以被提升为int类型,但是int类型不可以转换为枚举类型
int color = blue; //blue是枚举常量,color是int变量
band = 3; //3是int类型,band是枚举类型,不能将int转换为枚举
color = 3 + red; //正确使用,运算前red由枚举类型转换为int类型,再进行运算
band = orange + red; //错误使用,枚举没有算术运算符,且运算前orange和red转换为int类型了
设置枚举量的值
使用赋值运算符来显式地设置枚举量的值:
enum bits {one = 1, two = 2, four = 4, eight = 8}; //指定的值必须是整数
enum bigstep {first, second = 100, third}; //first默认为0,没被初识化的枚举量的值比前面的枚举量大1,故third值为101
enum spectrum {zero, null = 0, one, numero_uno = 1}; //这属于正确设置枚举量的值
枚举的取值范围
enum bigstep {first, second = 100, third};
枚举取值范围的定义:上限,找出枚举量的最大值,然后找到大于这个最大值的、最小的2的幂,将他减1,例如:bigstep中最大枚举值是101,在2的幂中,比这个数大的最小值为128,因此取值范围为127;下限,找出枚举量的最小值,如果它不小于0,则取值范围下限为0,否则,采用与寻找上限一样的方式,弹药加上负号,例如:如果最小值是-6,而比它小的、最大的2的幂是-8,因此下限为-7。
enum bits {one = 1, two = 2, four = 4, eight = 8};
bits myflag;
myflag = bits(6); //属于正确的赋值,虽然6不是枚举值,但6在枚举的取值范围之内,可以使用

浙公网安备 33010602011771号