c++指针和const的几种用法

指针和const

如果值没有被const修饰,但指针认为指向了一个被const修饰的值,这是合法的;但反过来,值被const修饰而指针认为指向了一个没有被const修饰的值,这是不合法的。

对比两种情况:

int age = 20;
const int * pt = &age; // 合法 但认为pt指向const int 所以无法通过pt修改age
const int age = 20;
int * pt = &age; // 不合法 因为非const指针不能指向const

于是在函数传参时有以下情况:

void foo(int *a);
int b = 10;
foo(&b); // 合法 用int *接int *
const int c = 11;
foo(&c); // 不合法 用int * 接 const int *
void foo(const int *a);
int b = 10;
foo(&b); // 合法 
const int c = 11;
foo(&c); // 合法

不同位置的const

int age = 20;
const int * pt = &age; // pt指向一个const int 但自身非const
int * const ps = &age; // pt指向一个int 自身被const修饰
const int * const pq = &age; // pt指向一个const int 自身被const修饰

如果不是指针,那么const位置不同没有区别,都是值被const修饰

// 没有区别
const int a;
int const a;

函数和二维数组

数组名被视为其地址,因此相应的形参是一个指针。问题在于对于二维数组,如何正确声明指针。

int data[100][4];
int (*pt)[4] = data;

同样在函数传递时,如果要传递二维数组,也要用同样的方法声明指针。

// 以下两种声明等价
int sum(int (*ar)[4]);
int sum(int ar[][4]);
sum(data);

ar指向数组(由4个int组成的数组),在获取数据时,需要对指针ar执行两次解除引用,才能得到数据。

ar[r][c] == *(*(ar + r) + c); // 两者等价

函数指针

void foo(const int *x);
void (*pt)(const int *); // 定义函数指针
pt = foo; // 赋值
int a =  10;
// 以下两种写法等价 但第一种写法更明显提示了当前正在使用函数指针
// 第一种写法认为pf是指针,*pf是函数
// 第二种写法认为函数名foo是指向该函数的指针,那么指针pf应和函数名foo对等
// 实际上两种写法逻辑上冲突 但C++进行了折衷 即两种方式都是正确的
(*pt)(&a);
pt(&a);

函数前后const的作用

const int *代表一个指向(const int)的指针,但指针本身是可修改的。

为了安全性的考虑,c++不允许出现用int *去接const int *的情况。这不难理解,如果允许(int *) = (const int *),那么对*(int *)的修改会间接导致一块被认为是const int的内存空间被修改,这是不安全的。

const int *foo() {
    int *pt = new int();
    return pt;
}
int * pt = foo();// 不合法 不能用int *接const int *

函数后的const只用于成员函数,表示函数不能修改成员变量

class A {
private:
    int a;
public:
    void foo() const {
        a++; // 不合法 函数不能修改成员变量
    };
};