2 复合类型
2.1 数组
数组是一种数据格式,可以存储多个同类型的值。
2.1.1 一维数组
2.1.1.1 声明数组
typename arrayname[arraysize];
其中arraysize必须是在编译时已知的,因此arraysize可以是整型常数 or const值 or 常量表达式但不能是变量。
2.1.1.2 访问数组元素
arrayname[index]:index就是元素的下标,下标从0开始。
2.1.1.3 数组的初始化
1.只有在定义数组时才可以使用初始化,此后就不能使用了,也不能将一个数组赋值给另一个数组;但是可以使用下标分别给数组中的元素赋值
int cards[4] = {1,2,3,4};
2.初始化数组时,如果提供的值少于数组的元素数目,那么数组中前几个元素将被一一赋值,其他的数组元素将被赋值为0
int cards[4] = {1,2};
3.如果在声明数组时初始化数组,允许不提供arraysize,由编译器计算有多少元素。但是这种情况一般不太推荐,因为你可能不小心少输入了元素。
int cards[] = {1,2,3,4};
4.C++11初始化数组:
- 1.允许省略赋值操作符
int cards[4] {1,2,3,4};
- 2.允许大括号中不含数据,这将把所有元素赋值为0
int cards[4] {};
- 3.禁止缩窄转换(见自动类型转换)
int cards[4] {1,2,3.0,9};//not allowed,不能将浮点类型==>int类型(缩窄转换)
- 4.C++标准库(STL)提供了数组替代品—模板类vector;C++11新增了模板类array;这些会单独出笔记。
2.1.2 二维数组
2.1.2.1 二维数组的定义及初始化
二维数组定义及初始化,此处使用了指针数组
可以使用数组的数组
char cities[Cities][25] = // array of 5 arrays of 25 char
{
"Gribble City",
"Gribbletown",
"New Gribble",
"San Gribble",
"Gribble Vista"
};
还可以使用string对象数组
const string cities[Cities] = // array of 5 strings
{
"Gribble City",
"Gribbletown",
"New Gribble",
"San Gribble",
"Gribble Vista"
};
由于string对象数组使用自动内存分配,指针数组使用的指针,因此这两者字符串的存储空间根据字符串大小而定,比较经济。
2.1.2.2 二维数组的遍历
使用for循环遍历。
2.1.2.3 数组与指针
见指针。
2.2 字符串
2.2.1 字符串定义
's’单引号引的一个字符叫做字符常量
char data = 'b'
"s"双引号引的叫做字符串常量,它是由’s’+'\0’组成
字符串就是以空字符串(null character)结尾,即\0,其ASCII码为0。
在初始化字符串时,一定要注意给\0留空间
char dog[3] = {'a','b','c'};//不是字符串
char dog[3] = {'a','b','\0'};//是字符串
char fish[] = "Bubbles";//双引号赋值的字符串不用手动添加空字符串结尾,系统自动生成。
2.2.2 拼接字符串常量
cout<<"I loke you"" and you like me!"<<endl;
cout<<"I loke you"
" and you love me"<<endl;
cout<<"I loke you and you like me!"<<endl;//这个和上面两句等价
2.2.3 在数组中使用字符串
1.用字符串常量初始化数组
2.将键盘或文件输入读入到数组中(见cin的用法)
2.2.4 raw(原始)字符串
在字符串中添加的转义字符会被编译器翻译为别的含义(\n翻译为换行),无法显示原始字符’\n’.
因此C++11提出了原始字符串,原始字符串使用R"(内容)"作为定界符,内容中可以包含\n将被保留原始字符’\n’。
如果要在原始字符中包含)“时,必须使用R”+(内容)+"作为定界符。
2.2.5 字符数组相关函数
和string类的赋值、拼接和附加一样。string类。
strlen(str)—计算并返回str数组长度,不包含\0
strcpy_s(str1,n,str2)—将长度为n的str2复制给str1
strcat_s(str1,n,str2)—将长度为n的str2追加到str1末尾
strncpy_s(str1,str2,n)—将长度为n的str2复制给str1
strcmp(str1,str2)—比较字符串str1与str2是否相等,是对字符串一个字母一个字母比较,遇到str1的第n个字母小于str2的第n个字母,则认为str1<str2;反之str2>str1。
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
2.2.6 string类简介
2.2.6.1 string类定义
在头文件中定义了string类,string类位于std名称空间中。
string对象与字符数组之间的主要区别是,可以将string对象声明为简单变量,而且程序能够自动处理string的大小。
2.2.6.2 string类初始化
- 1.使用C-风格字符串初始化string对象
- 2.使用cin键盘输入存储到string对象
- 3.C++11字符串初始化
2.2.6.3 string对象赋值、拼接和附加
- 1.赋值:不能将一个数组赋值给另一个数组,但是可以将一个string赋值给另一个string
- 2.拼接:可以使用+运算符将两个string拼接起来
- 3.附加:可以使用+=运算符将字符串附加到string对象的末尾
2.2.7 指针与字符串
见指针。
2.3 结构体
2.3.1 结构体定义
结构体可以包含任意类型的变量,甚至还可以包含成员函数(但是这点更好的实现是类,所以不深入研究)。
关键字为struct,下式定义为typename新类型,新类型typename包含成员var1,var2,var3
struct typename
{
char var1[20];
float var2;
double var3;
}
2.3.2 创建结构体变量及初始化
使用大括号{}初始化。
2.3.3 获取结构体元素
typename.var — 使用.成员运算符
2.3.4 成员赋值(memberwise assignment)
将结构体中的每个成员都设置为另一个结构体中相应的变量的值。
2.3.5 匿名结构体
不给结构体类型取名,直接定义结构体类型的同时创建结构体。缺点是不能在其他地方创建该结构体类型,因此C++中不常用。
2.3.6 结构数组
以结构体为元素的数组。
2.3.7 位字段
指定占用特定位数的结构体成员,位字段的类型位整型或枚举,格式为:字段:数字,可以使用没有名称的字段来提供间距。
2.4 共用体
是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。
当数据项使用两种或多种格式时,可节省空间。
eg:小商品目录,有一些商品的ID为整数,另一些ID为字符串。
匿名共用体没有名称,其成员将成为位于相应地址处的变量。
2.5 枚举
2.5.1 简介
是一种创造符号常量的方式
- 1.各个符号常量默认对应整数值0~一个正整数(7–以下第一个枚举)
- 2.对于枚举,只定义了赋值语句,没有定义算数运算
- 3.只能将定义枚举时使用的枚举量赋给这种枚举的变量;枚举是整型,可以提升为int类型,但是int类型不能自动转换为枚举类型或赋值给枚举
- 4.强制类型转换—可以将int类型数据强制类型转换为枚举类型
- 5.可显式指定整数值(int and long and long long)来覆盖默认值,后面没有被初始化的枚举量的值将比它前一位的枚举量大1
- 6.可以创建多个值相同的枚举量
- 7.枚举的取值范围:上限–找到枚举量的最大值,找到大于这个最大值的最小2的幂,将它减1,即为上限
下限–如果最小枚举量不小于0,则下限为0;反之找到小于最小枚举量的最大2的幂,将它加1,即为下限 - 8.存储枚举的空间大小由编译器决定
2.5.2 作用域内枚举
目的是减少名称冲突
enum Old1 {yes, no, maybe}; // traditional form
enum class New1 {never, sometimes, often, always}; // new form
enum struct New2 {never, lever, sever}; // new form
使用是需要使用::操作符:New1::never New2::never
2.6 const关键字
2.6.1 简介
格式:
const type name=value
特点:常量被初始化后,值被固定,编译器不允许再修改该常量的值
相比于define,使用const的好处:
- 1.能够明确指定类型
- 2.C++的作用域将定义限制在特定的函数或文件中
2.6.2 关于几种常指针的定义
- 1.定义一种常指针,使得不能使用该指针改变其指向存储位置的值,但是可以改变指针指向的存储位置,原变量也可以改变值
int age = 39;
int sloth = 3;
const int * pt = &age;// a pointer to const int
pt = 20;//invalid
pt = &sloth;//valid
- 2.定义一种常指针,使得能够使用该指针改变其指向存储位置的值,但是不能改变指针指向的存储位置
int sloth = 3;
int age = 39;
int * const finger = &sloth; // a const pointer to int
*finger = 80;//valid
finger = &age;//invalid
- 3.定义一种常指针,既不能使用该指针改变其指向存储位置的值,又不能改变指针指向的存储位置
double trouble = 2.0E30;
int age = 39;
const double * const stick = &trouble;
stick = &age;//invalid
*stick = 90;//invalid
2.6.3 关于(常)指针和(常)变量的之间赋值
- 1.非常变量的地址可以赋给常变量指针
int age = 39;
const int * pt = &age;//valid
- 2.常变量地址只能赋给常变量指针,不能赋给非常变量指针
const float g_earth = 9.80;
const float * pe = &g_earth; // VALID
const float g_moon = 1.63;
float * pm = &g_moon; // INVALID
- 3.不能将非常变量指针的地址赋给常变量指针的指针
const int **pp2;
int *p1;
const int n = 13;
pp2 = &p1; // not allowed, but suppose it were
*pp2 = &n; // valid, both const, but sets p1 to point at n
*p1 = 10; // valid, but changes const n
这就导致修改了常变量n的值,是不符合程序规则的。
2.6.4 尽可能使用const
- 1.这样的话可以避免无意间修改数据而导致的编程错误
- 2.使用const使得函数能够处理const和非const实参,否则只能接受非const数据。
2.7 举例
代码:
/*
Project name : _7compound_types
Last modified Date: 2022年3月13日17点04分
Last Version: V1.0
Descriptions: 各种复合类型
*/
#include<iostream>
int main()
{
using namespace std;
/*
数组:数组是一种数据格式,可以存储多个同类型的值。
一维数组:
声明数组:typename arrayname[arraysize];其中arraysize必须是在编译时已知的,因此arraysize可以是整型常数 or const值 or 常量表达式但不能是变量。
访问数组元素:arrayname[index]:index就是元素的下标,下标从0开始。
数组的初始化:
1.只有在定义数组时才可以使用初始化,此后就不能使用了,也不能将一个数组赋值给另一个数组;但是可以使用下标分别给数组中的元素赋值
int cards[4] = {1,2,3,4};
2.初始化数组时,如果提供的值少于数组的元素数目,那么数组中前几个元素将被一一赋值,其他的数组元素将被赋值为0
int cards[4] = {1,2};
3.如果在声明数组时初始化数组,允许不提供arraysize,由编译器计算有多少元素。但是这种情况一般不太推荐,因为你可能不小心少输入了元素。
int cards[] = {1,2,3,4};
4.C++11初始化数组:
1.允许省略赋值操作符
int cards[4] {1,2,3,4};
2.允许大括号中不含数据,这将把所有元素赋值为0
int cards[4] {};
3.禁止缩窄转换(见自动类型转换)
eg:int cards[4] {1,2,3.0,9};//not allowed,不能将浮点类型==>int类型(缩窄转换)
5.C++标准库(STL)提供了数组替代品---模板类vector;C++11新增了模板类array;这些会单独出笔记。
二维数组:
二维数组的定义
二维数组初始化
二维数组的遍历
二维数组的使用
数组与指针,见_9pointer。
*/
cout << "数组***********************************************************************************" << endl;
cout << "初始化数组*****************************************************************************" << endl;
//初始化
int cards[4] = { 1,2,3 };
//使用下标给元素赋值
cards[3] = 10;
//使用下标访问元素
cout << "cards[3] = " << cards[3] << endl;//cards[3] = 10
//C++11语法初始化数组
int numbernew[4]{ 5,6,7,8 };
const int Cities = 5;
const int Years = 4;
const char* cities[Cities] = // array of pointers
{ // to 5 strings
"Gribble City",
"Gribbletown",
"New Gribble",
"San Gribble",
"Gribble Vista"
};
/*
*/
//二维数组定义及初始化
int maxtemps[Years][Cities] = // 2-D array
{
{96, 100, 87, 101, 105}, // values for maxtemps[0]
{96, 98, 91, 107, 104}, // values for maxtemps[1]
{97, 101, 93, 108, 107}, // values for maxtemps[2]
{98, 103, 95, 109, 108} // values for maxtemps[3]
};
//二维数组的遍历
cout << "Maximum temperatures for 2008 - 2011\n";
for (int city = 0; city < Cities; ++city)
{
cout << cities[city] << ":\t";
for (int year = 0; year < Years; ++year)
cout << maxtemps[year][city] << "\t";
cout << endl;
}
/*
字符串:
字符串定义:
's'单引号引的一个字符叫做字符常量
char data = 'b'
"s"双引号引的叫做字符串常量,它是由's'+'\0'组成
字符串就是以空字符串(null character)结尾,即\0,其ASCII码为0。
在初始化字符串时,一定要注意给\0留空间
char dog[3] = {'a','b','c'};//不是字符串
char dog[3] = {'a','b','\0'};//是字符串
char fish[] = "Bubbles";//双引号赋值的字符串不用手动添加空字符串结尾,系统自动生成。
拼接字符串常量:
cout<<"I loke you"" and you like me!"<<endl;
cout<<"I loke you"
" and you love me"<<endl;
cout<<"I loke you and you like me!"<<endl;//这个和上面两句等价
在数组中使用字符串:
1.用字符串常量初始化数组
2.将键盘或文件输入读入到数组中(见_6cin_usage)
raw(原始)字符串:
在字符串中添加的转义字符会被编译器翻译为别的含义(\n翻译为换行),无法显示原始字符'\n'.
因此C++11提出了原始字符串,原始字符串使用R"(内容)"作为定界符,内容中可以包含\n将被保留原始字符'\n'。
如果要在原始字符中包含)"时,必须使用R"+*(内容)*+"作为定界符。
字符数组相关函数:和string类的赋值、拼接和附加一样。见_8string_obj
strlen(str)---计算并返回str数组长度,不包含\0
strcpy_s(str1,n,str2)---将长度为n的str2复制给str1
strcat_s(str1,n,str2)---将长度为n的str2追加到str1末尾
strncpy_s(str1,str2,n)---将长度为n的str2复制给str1
strcmp(str1,str2)---比较字符串str1与str2是否相等,是对字符串一个字母一个字母比较,遇到str1的第n个字母小于str2的第n个字母,则认为str1<str2;反之str2>str1。
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
string类--见_8string_obj
指针与字符串---_9pointer
*/
cout << "字符串*****************************************************************************" << endl;
char dog[3] = { 'a','b','\0' };//是字符串
char fish[] = "Bubbles";//双引号赋值的字符串不用手动添加空字符串结尾,系统自动生成。
cout << "fish = "<<fish << endl;//fish = Bubbles
cout << "I loke you"" and you like me!" << endl;//I loke you and you like me!
cout << "I loke you"
" and you love me"<<endl;//I loke you and you like me!
cout << "I loke you and you like me!" << endl;//I loke you and you like me!
cout << "raw字符串******************************************************************" << endl;
cout << R"(jasmine \n is my English \t name!)" << endl;//jasmine \n is my English \t name!
cout << R"+*("(Who are you?)",she told.)+*" << endl;//"(Who are you?)",she told.
cout << "字符数组相关函数******************************************************************" << endl;
char char1[20] = { "Jamsine" };
char char2[20];
cout << "strlen(char1) = " << strlen(char1) << endl;//strlen(char1) = 7
strcpy_s(char2, 20, char1);
cout << "char2 = " << char2 << endl;//char2 = Jamsine
cout << "strcmp(char1, char2) = " << strcmp(char1, char2) << endl;
strcat_s(char1,20 , char2);
cout << "char1 = " << char1 << endl;//char1 = JamsineJamsine
cout << "strcmp(char1, char2) = " << strcmp(char1, char2) << endl;//strcmp(char1, char2) = 1
strncpy_s(char2, "Lily", 5);
cout << "char2 = " << char2 << endl;//char2 = Lily
cout << "strcmp(char1, char2) = " << strcmp(char1, char2) << endl;//strcmp(char1, char2) = -1
/*
结构体:
1.结构体定义:结构体可以包含任意类型的变量,甚至还可以包含成员函数(但是这点更好的实现是类,所以不深入研究)。
关键字为struct,下士定义为typename新类型,新类型typename包含成员var1,var2,var3
struct typename
{
char var1[20];
float var2;
double var3;
}
2.创建结构体变量及初始化:使用大括号{}初始化。
3.获取结构体元素 typename.var --- 使用.成员运算符
4.成员赋值(memberwise assignment):将结构体中的每个成员都设置为另一个结构体中相应的变量的值。
5.匿名结构体:不给结构体类型取名,直接定义结构体类型的同时创建结构体。缺点是不能在其他地方创建该结构体类型,因此C++中不常用。
6.结构数组:以结构体为元素的数组。
7.位字段:指定占用特定位数的结构体成员,位字段的类型位整型或枚举,格式为:字段:数字,可以使用没有名称的字段来提供间距。
*/
//定义结构体
cout << "结构体******************************************************************" << endl;
struct inflatable
{
char name[20];
float volume;
double price;
};
//创建结构体及初始化
inflatable structvar = { "Jasmine",9.99,999};
inflatable structvar1 = structvar;//memberwise assignment
//获取结构体元素
cout << "structvar1.name = "<< structvar1.name << endl;//structvar1.name = Jasmine
cout << "structvar1.volume = " << structvar1.volume << endl;//structvar1.volume = 9.99
cout << "structvar1.price = " << structvar1.price << endl;//structvar1.price = 999
//匿名结构体
struct {
char name[20];
int price;
} nonstruct = {"Booooo",999999};
cout << "nonstruct.name = " << nonstruct.name << endl;//nonstruct.name = Booooo
cout << "nonstruct.price = " << nonstruct.price << endl;//nonstruct.price = 999999
//结构数组
inflatable struct_group[2] = { {"baba",9.99,999999},{"mama",9.99,999999} };
cout << "struct_group[0].name = " << struct_group[0].name << endl;//struct_group[0].name = baba
cout << "struct_group[1].volume = " << struct_group[1].volume << endl;//struct_group[1].volume = 9.99
cout << "struct_group[0].price = " << struct_group[0].price << endl;//struct_group[0].price = 999999
//位字段
struct register_struct
{
unsigned int SN : 4;//SN占4位
unsigned int : 4;//4位未使用
bool goodin : 1;//goodin占1位
bool goodtorgle : 1; //goodtorgle占1位
};
//可以使用C++11的方式输入嘿嘿
register_struct data = { 9,true,false };
cout << "data.SN = " << data.SN<<endl;//data.SN = 9
/*
共用体:是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。
当数据项使用两种或多种格式时,可节省空间。
eg:小商品目录,有一些商品的ID为整数,另一些ID为字符串。
匿名共用体没有名称,其成员将成为位于相应地址处的变量。
*/
cout << "共用体******************************************************************" << endl;
union one4all
{
int int_val;
long long_val;
double double_val;
};
one4all pail;
pail.int_val = 99;//pail变量存储一个整型
cout << "pail.int_val = " << pail.int_val<<endl;//pail.int_val = 99
pail.double_val = 1.99;//pail变量存储一个浮点型,整型被丢弃
cout << "pail.double_val = " << pail.double_val<<endl;//pail.double_val = 1.99
//匿名共用体
struct widget
{
char brand[20];
int type;
union
{
long id_num;
char id_char[20];
};
};
widget prize;
prize.id_num = 999;//由于是匿名共用体,这里不需要使用类似于上面pail的中间标识符
cout << "prize.id_num = " << prize.id_num << endl;//prize.id_num = 999
strcpy_s(prize.id_char, 20, "99999");
cout << "prize.id_char = " << prize.id_char << endl;//prize.id_char = 99999
/*
枚举:是一种创造符号常量的方式
1.各个符号常量默认对应整数值0~一个正整数(7--以下第一个枚举)
2.对于枚举,只定义了赋值语句,没有定义算数运算
3.只能将定义枚举时使用的枚举量赋给这种枚举的变量;枚举是整型,可以提升为int类型,但是int类型不能自动转换为枚举类型或赋值给枚举
4.强制类型转换---可以将int类型数据强制类型转换为枚举类型
5.可显式指定整数值(int and long and long long)来覆盖默认值,后面没有被初始化的枚举量的值将比它前一位的枚举量大1
6.可以创建多个值相同的枚举量
7.枚举的取值范围:上限--找到枚举量的最大值,找到大于这个最大值的最小2的幂,将它减1,即为上限
下限--如果最小枚举量不小于0,则下限为0;反之找到小于最小枚举量的最大2的幂,将它加1,即为下限
8.存储枚举的空间大小由编译器决定
作用域内枚举:目的是减少名称冲突
enum Old1 {yes, no, maybe}; // traditional form
enum class New1 {never, sometimes, often, always}; // new form
enum struct New2 {never, lever, sever}; // new form
在使用是需要使用::操作符:New1::never New2::never
*/
cout << "枚举******************************************************************" << endl;
enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};//各符号常量对应于整数值0~7
spectrum band;//一个枚举变量
band = blue;//枚举变量的赋值
cout << "band =" << band << endl;//band =4
//band = 99;//not allowed
int var_int = blue;//allowed,blue自提升为int类型
cout << "var_int =" << var_int << endl;//var_int =4
//++band;//not allowed,枚举没有定义算数运算
//band = orange + red;//not allowed
band = spectrum(3);//强制类型转换--这里注意一定要保证3在枚举中是存在的,不然结果是不确定的
cout << "band = " << band << endl;//band = 3
enum bits {one=1,two=2,four=4,eight=8};//显式指定整数值
enum bigstep {first,second = 100,third};//first对应整数值0,third对应整数值101
enum data {zero,null=0,lala,numero_nuo=1};//zero对应整数值0,lala对应整数值1---多个值相同的枚举量
bits myflag;
myflag = bits(6);//这个是合法的,原因是6在该枚举的取值范围内。
cout << "myflag = " << myflag << endl;//myflag = 6,具体咋映射的好像需要自己写映射函数
return 0;
}
运行结果:
数组***********************************************************************************
初始化数组*****************************************************************************
cards[3] = 10
Maximum temperatures for 2008 - 2011
Gribble City: 96 96 97 98
Gribbletown: 100 98 101 103
New Gribble: 87 91 93 95
San Gribble: 101 107 108 109
Gribble Vista: 105 104 107 108
字符串*****************************************************************************
fish = Bubbles
I loke you and you like me!
I loke you and you love me
I loke you and you like me!
raw字符串******************************************************************
jasmine \n is my English \t name!
"(Who are you?)",she told.
字符数组相关函数******************************************************************
strlen(char1) = 7
char2 = Jamsine
strcmp(char1, char2) = 0
char1 = JamsineJamsine
strcmp(char1, char2) = 1
char2 = Lily
strcmp(char1, char2) = -1
结构体******************************************************************
structvar1.name = Jasmine
structvar1.volume = 9.99
structvar1.price = 999
nonstruct.name = Booooo
nonstruct.price = 999999
struct_group[0].name = baba
struct_group[1].volume = 9.99
struct_group[0].price = 999999
data.SN = 9
共用体******************************************************************
pail.int_val = 99
pail.double_val = 1.99
prize.id_num = 999
prize.id_char = 99999
枚举******************************************************************
band =4
var_int =4
band = 3
myflag = 6
D:\Prj\_C++Self\_7compound_types\Debug\_7compound_types.exe (进程 14616)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
3 README
此为本人读C++ Primer总结的笔记,如有错误或知识缺口,请在评论区告知。如本文有在实践中帮到您,是本人的荣幸。