明解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

正文完
 
评论(没有评论)