# C++基础2-复合数据类型

本文是《C++ Primer Plus》的笔记,本文中的案例均自己实践过,如需转发请在转发开头贴上原文地址,谢谢!

# 复合数据类型

# 数组

typeName arrayName[arraySize];
//example
int numArr[3];
//init way
int numArr[3]={1,2,3};
//列表初始化,C++11新特性,适用于所有类型
int numArr[3] {1,2,3};
1
2
3
4
5
6
7

# 字符串

# C++处理字符串第一种方式:

C-Style string。存储在Char数组中,以null character结尾。被写作'\0',ASCII码也为0。注意,如果这个数组不是以空字符结尾,用cout打印的话,还是会继续打印内存中后续的字符直到遇到空字符。

//这个不是字符串
char strArr[3] = {'h','i','h'}
//这个是字符串
char strArr[3] = {'h','i','\0'}
//初始化
char strArr[3] = "hi";
char strArr[] = "hi";
1
2
3
4
5
6
7

注意"h"和'h'是不一样的前者是字符串,包含'h'和'\0',后者是字符常量。在C++中字符串表示的是字符串所在的内存地址。

# 拼接字符串常量

任何两个由空格,制表符和换行符分隔的字符串常量都将自动拼接成一个字符串。

# 计算字符串长度
char calNum[10]="12345";
cout << strlen(calNum) << endl;
cout << sizeof(calNum) << endl;
1
2
3

第一个输出是5,不包含空字符。第二个输出是10。

# 字符串的输入问题
char n[20];
char m[20];
cin >> n;
cin >> m;

cout << n << endl;
cout << m << endl;

char oneline[20];
cin.getline(oneline, 20);
cout << oneline << endl;

char oneline1[20];
char oneline2[20];
cin.get(oneline1, 20);
cin.get();
cin.get(oneline2, 20);
cout << oneline1 << endl;
cout << oneline2 << endl;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

get和getline的区别是get将换行符还留在待输入队列中,第二个get再次读入还是这个换行符。但是使用get()可以跳过当前输入字符,哪怕是换行符。使用get()的好处是可以判断当前输入是超过字符还是正常输入结束。

如果遇到空行的话,或者输入的字符比指定的多,会设置失效位,接下来的输入会被阻断。如果想恢复输入,使用cin.clear()。

# C++处理字符串第二种方式:

C++98通过添加string类将字符串作为一种数据类型来处理,该类位于名称空间std中。

//初始化
string str1 = {"hello world"};
string str2 {"hi world"};
//赋值
str2 = str1;
//上面等价于
char[10] chrArr1;
char[10] chrArr2;
strcpy(chrArr2,chrArr1);
//如果后面的长度比前面的大会出问题,使用下面
strncpy(chrArr2,chrArr1);

string str3;
str3 = str1 + str2;
str2 += str1;
//上面等价于
strcat(chrArr2,chrArr1);
//如果拼接的字符串超出chrArr2的长度也会出问题,使用下面
strncat(chrArr2,chrArr1);

char charLen[20];
string strLen;
cout << strLen.size() << endl;
cout << strlen(charLen) << endl;
//上面的两种形式等价,但是输出结果却不一样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 字符串常量字面值

wchar_t name1[] = L"hello xie1";
char16_t name2[] = u"hello xie2";
char32_t name3[] = U"hello xie3";

cout << R"(hello "this" is a apple \n (what) do you think?)";
cout << R"+*( hello "this" is a apple \n "(what)" do you think? )+*";

wchar_t name4[] = LR"( hi,this is your name :)";
1
2
3
4
5
6
7
8

# 结构体

# 结构体声明与定义

//结构体的声明,声明的位置也很重要,外部声明和内部声明的范围不同
struct structName{
    typeName variableName1;
    typeName variableName2;
    typeName variableName3;
};

//结构体的定义
struct structName structVariable1; //C style
structName structVariable2; //C++ style

//声明和定义同时
struct structName{
    typeName variableName1;
    typeName variableName2;
    typeName variableName3;
}structVariable1,structVariable2;

//结构体数组
structName structArr[10];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

实例

struct student {
        string name;
        int age;
    }stu1 = {
        "stu1",
        14
    };

    struct student stu2 = {"stu2",16};
    student stu3 {"stu3",16};
    student stu4[2] = {
        {"stu4",18},
        {"stu5",20}
    };
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 结构中的位字段

位域允许我们使用以bit为单位来存储数据,为我们节省内存。

struct student2 {
    unsigned short name :3;
    unsigned int : 0;
    unsigned char sex : 1;
    unsigned int : 10;
    bool married : 1;
}stu2;
1
2
3
4
5
6
7
  1. 能够使用类域的是整型,字符型,布尔型。通常最好将位域设成unsigned。
  2. 位域字段从上往下定义在内存中是从低到高分配。
  3. 位域字段不能是类的静态成员,取地址符不能用在位域字段上。
  4. 位域的长度不能超过存储单元的长度。
  5. 空域(0长度位域)让数据从下一个存储单位开始。未命名位域将保留不使用。

# 共用体

union unionName{
    typeName1 variableName1;
    typeName2 variableName2;
    typeName3 variableName3;
}
1
2
3
4
5

匿名共用体(anonymous union)

struct student {
    string name;
    union {
        int age1;
        char age2;
    };
};
//如果把char换成string就会出错。
student stu ;
stu.age1 = 10;

//main函数中使用
union { int a; const char* p; };
a = 1;
p = "hello world";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 枚举

是由若干枚举常量组成的集合。


//在宏中使用#+类型名,可以将该类型转换成字符串
#define VNAME(value) (#value)
    enum weekdays {
        monday,
        tuesday,
        thursday
    };

//scoped enumeration
    enum class MColor {
        red=1,
        blue=2,
        green=4
    };

    weekdays wd;

    wd = tuesday;

    MColor mcolor;

//不能直接使用red,可以避免污染全局环境
    mcolor = MColor::red;

    cout << wd << endl;
    cout << VNAME(tuesday) << endl;

    if (wd == weekdays(1)) {
        cout << "hello world!" <<endl;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31