C++笔记

C++ Primer Plus笔记,学校编的教材讲的一言难尽

第二章

C语言中只写main()默认int main()

C++ main()与main(void)等效,而C语言则表示对是否接受参数保持沉默。

主函数的return 0;可以省略

注释

//是C++风格,/* */是C风格。

命名空间

using namespace std;

using std::cout;

格式化

一行代码中不可分割的元素叫做标记(token)。通常必须用空白(空格、制表符和回车)将两个标记分开。

第三章

以两个下划线或下划线和大写字母打头的名称保留给实现。以一个下划线开头的名称保留给实现,用作全局标识符。

命名约定俗成的一些规矩:n表示整型,str或sz表示字符串,b表示布尔值,p表示指针,c表示单个字符。

整数

C++提供了一种灵活的标准,确保了最小长度。

长度

使用sizeof运算符查看类型名或变量名长度

sizeof(int)sizeof test当查看变量名时,括号是可选的。

声明

C++在C之上增加了新的声明语法

1
int a(5);
1
2
int enum{5};
int syss={};

unsigned是unsigned int的缩写;

进制

第一位为1~9,则为十进制;第一位为0,第二位为1~7,则为8进制;前两位为0x或0X,则为16进制。

编译器通过数字后缀来分配变量长度

1
cout << sizeof 114514uLL << endl;

常见的后缀有u(unsigned int),l(long),ul(顺序无所谓,unsigned long),ull(unsigned long long)。

C++中,对不带后缀的十进制整数,将使用能够存储该整数的最小类型来表示,int,long,long long;对不带后缀的八进制或十六进制整数,将采用int,unsigned int,unsigned long,unsigned long long。

字符

可以使用八进制和十六进制编码表示转义序列,如\032\x1a

char在默认情况下既不是没有符号,也不是有符号。是否有符号由C++实现决定。

wchar_t表示宽字符类型,宽字符可以在字符或字符串前加个L标识,如L'p',输出显示字符串时使用wcout

常量

C++中使用const定义常量,不推荐使用#define

浮点数

浮点数有E表示法,如3.14E4等。

类型转换

在计算表达式时,C++将bool、char、unsigned char和short值转换为int。

强制类型转换有两种方式,

1
2
(long) thorn
long (thorn)

C++还引入了4个强制类型转换的运算符

1
static_cast<long>(thorn)

auto声明自动判断变量类型。

第四章

C++11初始化数组时可省略=

1
double a[2] {112,1123};

字符串拼接

任何两个由空白分隔的字符串常量将自动拼接成一个,第一个字符串末尾的\0会被取代。

字符串输入

cin使用空白作为分隔符,处理字符串输入。

读取中间含有空格的字符串可使用cin.getline()

一种变体

1
cin.get(a,20).get()

string类型

C++98添加了string类型

1
2
3
string str1;
cin >> str1;
cout << str1 << endl;

string可直接赋值,并且可通过+操作实现字符串拼接

1
2
3
4
string str1, str2, str3;
str1 = "Hello";
str2 = "World";
cout << str1 + " " + str2 << endl;

C++使用前缀u8表示Unicode字符串类型,还新增了原始字符串类型,原始字符串中的回车输出到屏幕上也是回车。

1
cout<<R"(1"\n")"<<endl;

如果想在原始字符串中包含”(、)”,可以通过在”和(之间添加其他字符修改标识符。

1
cout << R"1("()")1" << endl;

结构类型

1
2
3
4
5
6
7
8
9
10
11
12
13
struct abc
{
char a1;
int a2;
string a3;
};
abc x1 = {
'a',
114514,
"Hello"};
abc x2 {'b',1919810,"World"};
abc x3 {};
cout << x1.a1 << x1.a2 << x1.a3 << endl;

C++中定义结构可以省略struct,初始化时,等号可省略,使用空的大括号时,表示将所有元素初始化为0。

两个相同的结构之间可以互相赋值。

1
2
3
4
5
6
struct abc
{
char a1;
int a2;
string a3;
} a1{'c', 1, "2"};

定义结构时,可以同时声明变量并进行赋值。还可以省略结构名称。

结构数组

1
abc x4[2] = {{'d', 2, "CC"}, {'e', 4, "DD"}};

结构中的位字段

1
2
3
4
5
6
7
struct def
{
unsigned int : 4;
unsigned SN : 5;
bool goodIn : 1;
bool goodTorgle : 1;
};

共用体(节省空间)

1
2
3
4
5
6
7
8
9
union a
{
int a1;
long a2;
long long a3;
};
a c1;
c1.a3 = 1e14;
cout << c1.a3 << endl;

共用体的长度为其最大成员长度。

匿名共用体

1
2
3
4
5
6
7
8
9
10
11
12
struct unitest
{
char a;
union
{
int a1;
char a2[4];
};
double c1;
};
unitest test;
test.a1 = 3;

a1和a2位于相同的地址。

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enum spec
{
red,
orange,
yellow,
green
};
int main()
{
int a;
a = orange;
cout << a;
spec testvar;
testvar = spec(3);
return 0;
}

设置枚举类型的值

1
2
3
4
5
6
7
enum spec
{
red,
orange,
yellow=100,
green
};

这样red为0,orange为1,green为101;

可以创建多个值相同的枚举变量。

取值范围

枚举变量可取的值不一定是枚举定义中的值,可根据上界和下界确定枚举变量的取值范围。上界确定方法为,120->128,最大为127。如果枚举变量中最小值为正数,则下界为0,否则,下界确定的方法和上界相同。

指针

分配空间

1
int *p=new int;

在C++中,值为0的指针成为空指针。

使用delete释放内存只会释放内存空间,不会删除指针本身,可以指向别的内存地址。

不要重复释放内存(除非指针是空指针,这种情况可以)。

静态联编(编译时分配内存) VS 动态联编(运行时分配内存)

分配数组

1
2
3
int *p=new int [10];
...
delete [] p;

用引号括起来的字符串传递的是字符串首字符的地址。

动态结构

1
2
3
4
5
6
7
8
struct test
{
char cht;
int intt;
};
test *p = new test;
p->cht;
(*p).intt;

内存管理

C++中有三种管理数据内存的方法,自动存储、静态存储和动态存储。

自动存储

在函数内部定义的常规变量使用自动存储空间,被称为自动变量,通常存储在栈中。

静态存储

静态存储是整个程序执行期间都存在的存储方式,有两种方式,一是定义在函数外部,另一种方式是使用关键词static。

动态存储

使用new和delete分配和释放内存空间。

vector 和 array

1
vector<int> a(3);
1
array<int, 5> a1 = {1, 2, 3, 4, 5};

vector存储在堆中,array存储在栈中,两者均存在索引越界的问题,使用at方法可在索引前进行检查,但是会增加程序执行时间。

第五章

C++将赋值表达式的值定义为左侧成员的值。

递增/递减运算符

对于类而言,前缀版本效率比后缀版本高。

++p执行先将p指针++再取值,++\p表示先取值再++,*p++表示先取值,再对地址++。

逗号表达式

先计算第一个表达式,再计算第二个表达式。逗号表达式的值是第二部分的值。所有运算符中,逗号表达式的优先级是最低的。

关系运算符

关系运算符的优先级比算术运算符低。

类型别名

1
typedef typeName aliasName;

typedef不会创建新类型,只会为已有的类型创建一个新名称。

基于范围的for循环

1
2
3
4
5
double price[5] = {1.0, 2.0, 3.0, 4.0};
for (double x : price)
{
cout << x << endl;
}

如果检测到EOF,则将eofbit和failbit设置为1,因此可将cin.eof和cin.fail放在读取后。

第七章

当用于函数头和函数原型时,int * arrint arr[]是相同的。

传递数组时,函数中使用的是原数组。

可以使用void test(const int a [],int n)这样的方式禁止在函数内修改原数组的值。

1
2
int age=50;
const int *p=&age;

上边的这段代码无法通过p指针修改age变量的值,但是可以通过age变量进行修改。另外,

1
2
const int age=50;
int * p=&age;

这种情况是不允许的。

1
2
int age=50;
int * const p=&age;

这样声明的p指针只能指向age,但是age的值能通过p指针进行xiu’gai