C++

c++复习

c++

Posted by Jow on August 6, 2019

目录

  1. 头文件:climits
  2. 打印显示整形
  3. 数组
  4. 字符串
  5. 结构体
  6. 联合
  7. 枚举
  8. 指针
  9. 内存分配的方法
  10. 类型组合
  11. 数组的替代品

在烟花绽放的那一瞬间我仿佛看到自己最美好的时光,坚持奋斗在凌晨的自己,不知道什么是疲倦,只知道我想得到别人的认可。 在青烟弥漫的天空,嗅到一缕缕火药的味道,如同日落西山,这或许自己开始没落的开始,想起自己凌晨两点还在被窝里看小说的荒唐时光。 伴随着划破天空的声音,一颗烟花正在迅速的升空,这个阶段或许就是精致生活的开始,期待着自己的再次绽放。

头文件:climits

头文件clinits定义了符号常量来表示类型的限制。以char来举例子,其他的类似: climits文件中包含与下面类似的语句行:

1
#define INT_MAX 32767
符号常量 表示
CHAR_BIT char的位数
CHAR_MAX char的最大值
CHAR_MIN char的最小值
SCHAR_MAX signed char最大值
SCHAR_MIN signed char最小值
UCHAR_MAX unsigned char最大值

打印显示整形

cout « hex; –十六进制输出整数 cout « oct; –八进制输出整数

数组

数组的声明: typeNamearrayName[arraySize]; 在这里应该注意表达式arraySize执行元素数目,他必须是整形常数或者const值,也可以是常量表达式(如8*sizeof(int)),即在其中所有的值在编译时都是已知的。具体的说,arraySize不能是变量,变量的值是在程序运行时设置的。 数组值的初始化,可以使用花括号加逗号,进行多个值的初始化。当值初始化其中一部分的值的时候,默认的其他值将会被赋予0.因此将数组初始化为0非常的简单,只需要将一个值初始化为0就可以了. 如果初始化的时候方括号[]中数值为0,c++编译器将子酸元素的个数。

1
2
3
short things[] = {1,2,3,4}
double earnings[4] {1.2,1.6,1.1,1.7}
int a {10}

我们在使用花括号进行初始化话的时候可以带等号也可以不带等号,这个种方式一样的可以用在赋值方面.

字符串

在c++中,实现字符串有两种方式: 第一种是c的方式,使用一个char型数组直接赋值一个字符串,或者以花括号的形式,但是最后一个字符要是’\0’,空字符。 第二种是使用string库,这样可以直接使用声明string类型的字符串。

1
2
char str[8] = {"a","b","c","d","e","f","\0"}
char str1[8] = "abcdef"

字符串常量和字符常量是不能互换的,字符常量’S’是字符串编码的简写表示。而字符串”S”,表示两个字符字符S和空字符,”S”,实际上表示的是字符串所在的内存地址。 拼接字符串常量,有时候字符串很长,无法放到一行中。C++允许拼接字符串字面值,即将两个引号括起来的字符串合并为一个。事实上,任何两个由空白分隔的字符串常量都将自动拼接成一个。

在使用字符串的输入的时候,cin使用空白来确定字符串的结束位置,这意味着cin在获取字符数组输入时只读取一个单位,然后把剩下的遗留在输入队列当中,这样再有输入要求的时候,会自动把输入队列中的值赋值过去。这个时候我们就要使用其他函数来实现一个读取一行的字符串,他使用换行符确定行尾但是不保存换行符,与之功能相似的还有get函数,但是get函数不会丢弃换行符,所以我们需要再次通过一次读取来抛弃换行符:

1
2
3
cin.getline(name,20);
cin.get(name,20);
cin.get();

在混合输入数字和字符串的时候可能会导致空行问题,即只有一个换行符的行,所以需要收到去掉换行符才能继续输入。

使用string类来定义访问字符串:

  • 可以使用c风格字符串来初始化string对象
  • 可以使用cin来将键盘输入保存到string对象中
  • 可以使用cout来显示string对象
  • 可以使用数组表示法来访问存储在string对象中的字符。

使用string类可以自由的拼接字符串和赋值,使用数组的话,数组之间是不能将一个数组赋给另一个数组的。

结构的使用

1
2
3
4
5
6
7
8
struct inflatble {
	char name[20];
	std::string firstName;
	float volum;
	double price;
}
inflatble hat;
inflatble duck = {"Daphne", 0.12, 9.98};//等号是可选的

结构作为一种类型,也是可以声明为数组的。

共同体

共同体union是一种数据格式,它能够存储不同的数据类型,但是只能同时存储其中的一种类型。也就是说结构可以同时存储int、float、double,共同体只能存int、long或double。

1
2
3
4
5
6
7
8
9
union one4all{
	int int_val;
	long long_val;
	double double_val;
}

one4all pail;
pail.int_value = 15;
pail.doulbe_value = 15.5; //store a double, int is lost

共同体的大小取决于占用内存最大的元素,这些成员指向同一块内存,所以一次只能有一个成员有值,便于节约内存。

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum spectnum
{
	red, orange, yellow, green, blue, violet, indigo, uitraviolet
};
enum bits
{
	one = 1, two = 2, four = 4,eight = 8, nine
};
int main()
{
	spectnum color;
	color = orange;
	bits num;
	num = nine;
	cout << color<< num; \\ 输出:19
	return 0;
}

枚举的取值范围,首先要找出上限,需要知道枚举量的最大值。找到这个最大值的、最小的2的幂,将它减去1,得到的便是取值范围的上限。如果最大是101,比这个打的2次幂值是128,所以取值上限是127,与之对应,最小值,就是找到比最小值小的2次幂,在加1。

指针

一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。 下面这个就是个典型的错误的例子,只是声明的一个指针,这个指针的的地址并不知道,如果现在直接给这个指针指向的地址赋值将会导致出乎意料的问题。

1
2
3
4
5
6
long * fellow;
*fellow = 23333;

int *pn = new int;
int higgens;
int *pt = &higgens;

上面正确使用指针的方式,一个只能通过*pn来访问值,另一个可以通过higgens和*pt两种方式访问。 关于内存分配,变量和指针的内存分配是在栈上的,new出来的内存是在堆上的。 delete只能用来释放new分配的内存。然而,对空指针使用delete是安全的

1
2
3
4
5
6
int *pt = new int;
int *arr = new int[300]
delete []arr;
delete pt;
// arr[0] == *arr
// arr[1] == *(arr + 1)

关于delete的使用:

  • 不用使用delete来释放不是new分配的内存
  • 不要使用delete释放同一块内存两次
  • 如果使用new[]为数组分配内存,则应该使用delete[]来释放
  • 如果使用new为一个实体分配内存,则应该使用delete来释放
  • 对空指针应用delete是安全的

对于一个数据结构也是可以动态的使用new和delete创建删除的。

1
2
3
4
5
6
7
8
struct inflatable{
	char name[20];
	float volume;
	double price;
}

inflatable * ps = new infatable;

内存分配的方法

内存分配的方法一共有三种:自动存储、静态存储和动态存储。

  1. 自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量,这意味着它们所在的函数别调用时自动产生,在该函数结束时消亡,实际上自动变量是一个局部变量,其作用域为包含它的代码块。自动变量一般存储在栈中,这意味着执行代码块时,其中的变量将依次加入到栈中,而在离开代码块的时候按相反的顺序来释放这些变量。
  2. 静态存储:静态存储是整个程序执行阶段都存在的存储方式。一个是定义为全局变量,还有一种方式就是使用static定义为静态变量。
  3. 动态存储:new和delete运算符提供了一种比自动变量和静态变量更加灵活的方法。它们管理一个内存池,称之为自由存储空间或者堆。new和delete让你可以更加自由的分配内存,它们的声明后期不完全受程序或函数的生存时间控制。与常规变量相比,使用new和delete让程序员对程序拥有更大的控制权。在内存方面,在栈中,自动添加的删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占有的自由存储区不连续,这使得跟踪新分配内存的位置更加困难。

使用动态存储的方式很容易引起内存泄漏,特别是给指针申请了内存,然后没有释放的情况,这个时候智能指针可以解决这个问题,后面再进行学习介绍。

类型组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct test_year{
	int year;
}
test_year s1,s2,s3;
s1.year = 1995;
test_year *pa = &s1;
pa->year = 2019;
test_year arr[3];
arr[1].year = 2014;
(arr+1) -> year = 2015;
const test_year * arp[3] = {&s1,&s2,&s3};
const test_year ** ppa = arp;
(*ppa)->year;
(*(ppa+1))->year;
*ppa -> year;//会报错,因为ppa->year不是指针

访问指针中的成员可以直接使用指针加上间接成员运算符访问成员,如果不是指针的话可以使用成员访问符。

数组的替代品

模板类vector和array是驻足的替代品。

1
2
3
4
5
vector<int> vi;//创建一个0大小的数组
int n =10;
vectore<double> vd(n);//创建一个n大小的数组
array<int,5> ai;
array<double,5> ad;

vector的功能比array强大,但是相比于array效率较低。如果是定义定长的的数组,比起vector数组是更加的选择,但是代价是不那么的方便安全。这也就催生了array对象,array对象长度也是固定的,也是用栈而不是自由存储区,因此效率和数组相同,但更方便更安全。

无论是数组、vector还是array对象,都可以使用标准数组表示法来访问各个元素。array和数组存在栈中,而vector存储在堆中。array可以直接赋值给另一个array,但是数组就只能逐个拷贝.