《C++ Primer Plus(第六版)》(3)(第四章 复合类型 笔记)

时间:2022-08-27 08:23:17

这章既熟悉又陌生,数组在大学之后用的多,毕业之后几乎没用过了。
1.不能将一个数组赋值给另一个数组。

int a[5] = { 1, 2, 3, 4 };
char b[4] = { 'a' };
char c[10];//未初始化的字符好像经常会显示“烫烫烫烫烫”,哈哈哈哈哈哈哈哈哈哈哈
int d[4];//未初始化的int经常是-858993460。
百度一下:
烫烫烫和屯屯屯产生自VC,这是debug模式下VC对内存的初始化操作。
VC会把栈中新分配的内存初始化为0xcccccccc,而把堆中新分配的内存初始化为0xcd。
把0xcc和0xcd按照字符打印出来,就是烫和屯了。
还有锟斤拷,这个是字符编码造成的。在进行从老的编码体系到unicode的转换过程中,
部分字符不能转化,于是unicode给了它们一个特殊的占位符U + FFFD,这个用UTF - 8表示就成了\xef\xbf\xbd。
如果出现两个连着的\xef\xbf\xbd\xef\xbf\xbd,按照两个字节一个字显示成汉字,就成了锟斤拷这三个字。
而0xcccccccc用int格式就是-858993460了。。。
设计成0xcccccccc是有特殊用意的……这个好像叫做Poison,未初始化的Pointer去取值的话会出错。
肯定有人问为什么不弄成0x00000000,因为空指针是指针的有效状态,可能会误导人,
而0xCCCCCCCC在Windows下永远不可能是一个指针的有效状态(不是NULL,不指向一个对象,不指向一堆对象紧接之后的区域),这就是在模拟野指针


2.string是以\0结尾的,char[]没有特别赋值的话,是没有的。

	char a2[5] = { 'a', 'b', 'c', 'd', 'e' };
	char b2[5] = { 'a', 'b', 'c', 'd', '\0' };
	cout << a2 << endl;
	cout << b2 << endl;
cout的时候,a2是没有结尾的,所以会一直往下走,知道出现一个\0为止。

《C++ Primer Plus(第六版)》(3)(第四章 复合类型 笔记)
每一次运行的结果可能都不同。


3.C++对字符串的长度没有限制,处理的时候碰到\0就会结束。


4.字符串常量,隐式添加了\0。例如‘S’和“S”是不同的,“S”中实际是两个字符,S和\0。\0只会在末尾出现,两个字符串拼接,则中间是没有\0的。


5.通过cin输入的字符串,用空字符(空格、回车、制表符等)来结尾。

	char a2[25] ;
	char b2[25] ; 
	cout << "input name:" << endl;
	cin >> a2;
	cout << "input school" << endl;
	cin >> b2;
	cout << "name:" << a2 << endl;
	cout << "school:" << b2 << endl;
结果是:

《C++ Primer Plus(第六版)》(3)(第四章 复合类型 笔记)
输入的fable game之后,就跳过了。

这个数组超过25个之后居然还能正常输出。只不过后面就跟着中断了。


6.位字段,真惭愧,第一次听说到这个东西。每个字段占的内存是按位来算的,不是原来基础类型的字节大小。在成员名后面加个:和位数就可以了。

一般用于硬件编程了,已经非常非常底层了。怪不得还没听说过。

typedef struct bit_field {
unsigned int a : 5;
unsigned int b : 3;
unsigned int c : 20;
unsigned int d : 4;
} bit_field_s;

7.共同体,用于节省内存。还是没有用过。。。。。。


8.枚举形的强制类型转换,好像是没有任何异常检测和抛错什么的。。。

	enum EMyEnum
	{
		EMyEnum1,
		EMyEnum2,
		EMyEnum3,
		EMyEnum4,
	};
	EMyEnum a = EMyEnum(5);
结果a的值是5.
这个平时写代码经常用到,自己写代码检测又嫌麻烦。只能自己把握了。


9.指针的声明,每一个变量都要带*

	int i = 123;
	int* p1, p2;
	p1 = &i;
	p2 = &i;//这一句编译不过,因为p2是int,而不是int*

10.new分配的内存一般都在堆(heap)或者*存储区中,变量声明的内存一般都在栈(stack)中。


11.C++3中管理内存的方式:自动存储,静态存储,动态存储。

    a.自动存储:局部变量,放在栈中,后进先出。函数被退出栈,变量就没了。

    b.静态存储:static,或者写在函数外

    c.动态存储:new出来的都是,放在堆中。

#include "Chapter4.h"
#include <iostream>
#include "Chapter2.h"
using namespace std;
class CTest
{
public:
	CTest(char c);
	~CTest();
	static CTest* getACTest();
private:
	char flag;
};

CTest::CTest(char c)
{
	flag = c;
	cout << "create CTest, flag:" << flag << endl;
}

CTest::~CTest()
{
	cout << "delete CTest, flag:" << flag << endl;
}

CTest* CTest::getACTest()
{
	CTest b('b');
	CTest* c = new CTest('c');
	return c;
}

static CTest a('a');
void CChapter4Answer::answer()
{
	CTest* c = CTest::getACTest();
	CTest d('d');
}
试了一下,各个地方的变量什么时候创建和删除。

最后得到的结果:

《C++ Primer Plus(第六版)》(3)(第四章 复合类型 笔记)
因为a是静态变量,所以程序启动的时候先创建了a,然后才进入main函数。

在getTest函数内先创建了b,然后new了一个c。b是声明出来的,所以函数结束之后,就会删除掉,而c是new出来的,放在堆中。

然后创建d,删除d,其实d就是在一个更大的函数内而已。

然后走完main函数,在外面才删除了a。静态变量是在关闭程序的时候才回收的。

然后c呢,c的析构函数没有走到。证明在堆中的内存,程序是不会回收的,这就是内存泄露了吧。相信操作系统会回收吧。

另外,走出了main函数之后,还是有别的操作的。这真是第一次知道。

要人工确保new和delete,对于稍微大一点的程序来说,应该不大可能吧。一般都会用智能指针,所以我在工作中,根本没有主动使用过delete这个关键字。

但是即使是智能指针,还是会出现内存泄露的情况。最先想到的就是两个智能指针互相指向,都在等对方释放。


12.vector初始化可以用{}直接包含一些元素进去。

	CTest* c = CTest::getACTest();
	CTest d('d');

	vector<CTest> e = { d };//这个很方便