明解C++(7-8章)

第7章 指针

  • 对象是用来存贮值的内存空间
  • 使用&xx 获取对象xx的内存地址(使用取址运算符&获取对象的地址),可以使用sizeof获取对象的内存空间大小为多少字节,1字节=8位(1 byte = 8bit)。指针是为了有效的利用地址
  • 用类型 int* pti; 定义指向int类型的指针,用 pti=&i 初始化指针值,即: &i 创建了指向int的指针
  • 指针的具体值是所指向对象的地址,*pti 为解引用运算,得到的是指针pti所指对象的值,*pti可以看作是变量i的别名
  • *解引用运算不但可以指向值,也可以指向函数,把函数作为一个变量即可。
  • 未初始化指针的情况下会得到不可预知的结果
  • 利用指针可以实现在运行时动态确定访问的对象
#include <iostream>
#include <typeinfo>
using namespace std;


int main() {
	int i=1,j=2;
	int* pti;
	double d;

	cout << "address if i:" << &i << ",size if i is:" << sizeof(i) << endl;
	cout << "address if j:" << &j << ",size if j is:" << sizeof(i) << endl;
	cout << "address if d:" << &d << ",size if d is:" << sizeof(d) << endl;
	cout << endl;

	pti = &i; cout << "pti=" << pti << ",*pti=" << *pti<<endl;
	pti = &j; cout << "pti=" << pti << ",*pti=" << *pti << endl;
	cout << endl;

	cout << "type of i:" << typeid(i).name() << endl;
	cout << "type of &i:" << typeid(&i).name() << endl;
	cout << "type of pti:" << typeid(pti).name() << endl;
	cout << "type of *pti:" << typeid(*pti).name() << endl;

	return 0;
}
/*
address if i:0000004ECE9DF8E4,size if i is:4
address if j:0000004ECE9DF904,size if j is:4
address if d:0000004ECE9DF948,size if d is:8

pti=0000004ECE9DF8E4,*pti=1
pti=0000004ECE9DF904,*pti=2

type of i:int
type of &i:int * __ptr64
type of pti:int * __ptr64
type of *pti:int
*/

用地址作为函数参数,可以实现对调用函数传入的参数的原始值的修改:

#include <iostream>
using namespace std;

void sum_times(int x, int y, int* sum, int* times) {
	// sum,times 为调用该函数的原始函数的两个变量的地址
	// 计算x,y 的和、乘积,并传给调用函数的 sum,times 两个变量
	*sum = x + y;
	*times = x * y;
}


int main() {
	int i=5,j=6;
	int s,t;
	double d;

	sum_times(i, j, &s, &t);

	cout << "s=" << s << endl;
	cout << "t=" << t << endl;

	return 0;
}
/*
s=11
t=30
*/

指针和数组

  • 一般情况下数组名即指针:数组名被解释为指向该数组的第一个元素的指针,即 a==&a[0]

  • sizeof(数组名) 返回数组整体大小而不是第一个元素大小

  • typeid(数组名)返回数组相关信息而不是第一个元素相关信息

  • &数组名是指向数组的整体指针,而不是指向第一个元素的指针

  • 可以用数组名作为参数,在函数间传递数据

#include <iostream>
using namespace std;

void reverse(int a[],int len_a) {
	//反转整数数组
	//int len_a = sizeof(a) / sizeof(a[0]);// 不能在这里计算数组长度,会得到2
	cout << "len of array:" << len_a << endl;
	int temp;

	for (int i = 0; i < len_a / 2; i++) {
		temp = a[i];
		a[i] = a[len_a - i - 1];
		a[len_a - i - 1] = temp;
	}
}

int main() {
	int a[10];
	int len_a = sizeof(a) / sizeof(a[0]);
	for (int i = 0; i < 10; i++) a[i] = i + 1;
	for (int i = 0; i < 10; i++) cout<<a[i]<<' ';
	cout << endl;

	reverse(a,len_a);
	for (int i = 0; i < 10; i++) cout << a[i] << ' ';

	return 0;
}
/*
1 2 3 4 5 6 7 8 9 10
len of array:10
10 9 8 7 6 5 4 3 2 1
*/

动态存储期

  • 程序员自由的控制对象的生命周期: 用 new Type 创建Type对象,并返回对象的地址。(C语言中用malloc 和 free 分配、释放内存空间)

动态创建变量:

#include <iostream>
using namespace std;

int main() {
	int* x; // 创建一个整数地址变量
	int* y;
	int* z;
	x = new int; //把申请的int地址赋值给x, *x 即创建的对象的值
	y = new int();
	z = new int(20);
	cout << "x:" << x << endl;
	cout << "*x:" << *x << endl; //这时候是一个不可预期的值
	*x = 10;
	cout << "*x:" << *x << endl;

	cout << "y:" << y << endl;
	cout << "*y:" << *y << endl;

	cout << "z:" << z << endl;
	cout << "*z:" << *z << endl;

	delete x, y, z; // 销毁创建的x指向的对象

	//cout << "*x:" << *x << endl; // 编译并不会错误,运行会触发异常
	return 0;
}
/*
x:000001CB87D66E30
*x:-842150451
*x:10
y:000001CB87D70820
*y:0
z:000001CB87D6EA90
*z:20
*/

动态创建数组:

#include <iostream>
using namespace std;

int main() {
	//动态数组
	double* array_double;
	int len_a;
	cout << "请输入浮点数组长度:" << endl;
	cin >> len_a;
	array_double = new double[len_a];//为数组分配空间

	for (int i = 0; i < len_a; i++) {
		array_double[i] = (i+1) * (i+1);
	}

	for (int i = 0; i < len_a; i++) {
		cout<<array_double[i] <<" ";
	}
	cout << endl;

	delete[] array_double;
	return 0;
}
/*
请输入浮点数组长度:
20
1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400
*/

分配失败会抛出异常,对应的分配的内存上线并不是物理内存,而是虚拟内存上限。

#include <iostream>
using namespace std;

int main() {
	//动态数组
	double* array_double;
	
	while (true) {
		try {
			array_double = new double[10000];//为数组分配空间
		}
		catch (bad_alloc) {
			cout << "创建动态数组失败" << endl;
			return 1;
		}
	}

}

分配失败,如果创建对象时指定 nothrow, 则返回空指针NULL而不是抛出异常。NULL 需要引入 或其他定义了NULL的库

#include <iostream>
#include <cstddef>
using namespace std;

int main() {
	//动态数组
	double* array_double;
	
	while (true) {
		array_double = new(nothrow) double[1000000];//为数组分配空间
		if (array_double == NULL) {
			cout << "动态数组创建失败" << endl;
			return 1;
		}
	}

}

可以指向任意类型的指针类型 void*

  • 可以赋值任意类型指针给 void*类型指针
  • 反过来需要进行显式的转换: pi = reinterpret_cast<int*>(pv)
  • void* 只能保存指针,不能进行*pv 取值
#include <iostream>
using namespace std;

int main() {
	int* pi;
	void* pv;

	int a = 5,b=10;
	pi = &a;
	pv = &b;
	cout << *pi << endl;
	cout << *(reinterpret_cast<int*>(pv)) << endl;

	return 0;
}
/*
5
10
*/

第8章 字符串和指针

  • 字符串变量最后以空字符结尾
  • 空字符是字符编码为0的字符,字面量为转义字符 ‘\0’
  • 字符串大小包含末尾的空字符

初始化字符串:

#include <iostream>
using namespace std;

int main() {
	char s1[] = { 'a','b','c','\0' }; //逐个字符初始化,需要加结束标志 '\0';
	char s2[] = { "abc" };
	char s3[] = "abc";
	char s4[6] = "abc";
	char s5[] = "abc\0def";

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;

	return 0;
}
/*
abc
abc
abc
abc
abc
*/

page277

正文完
 0