关于指针

为了弄明白** * & 等这些奇怪的符号的意思,比如下面这段leveldb代码

Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {
  *dbptr = nullptr;
// ...

每次看c cpp代码时都对这些”奇怪的”符号表示很难过,因为不是天天用这个做开发,弄明白后就忘记了,于是整理记录一下。

各种指针说明

  • 指针数组((存放)指针的数组,本质还是一个数组,加个的字就能好理解,下同)
  • 数组指针((指向)数组的指针)
  • 指针函数((返回)指针的函数)
  • 函数指针((指向)函数的指针)

各种指针的举例

引用自这里

int p; //这是一个普通的整型变量
int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级比*高,
// 所以P 是一个数组,然后再与*结合,
// 说明数组里的元素是指针类型,
// 然后再与int 结合,说明指针所指向的内容的类型是整型的,
// 所以P 是一个由返回整型数据的指针所组成的数组
int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂从P 开始,
//先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,
//说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,
//然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,
//然后再与*结合,说明数组里的元素是指针,然后再与int 结合,
//说明指针指向的内容是整型数据.所以P
//是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.
// 我注:这个没看懂。

几个要点

  • * 和 [] \ () 的优先级问题, *的优先级低,[]的优先级高。知道这个之后就能解决下面的区别了
     int *p[3]; // 先结合[] 说明主体是个数组, 那p就是指针的数据, 指向int型 的指针 的 数组  
     int  (*p)[3];  // 先结合* 说明主体是个指针  指向数组的指针
    int (*p)(int); // 同样,指向函数的指针。最后的括号里是参数类型列表。 第一个int是函数返回类型 
     ```  
     - int* p 与  int *p 一样。  也就是 * 靠着int 靠着p 还是一个都不靠 鲜果是一样的两个 * 的复合指针也是如此。   
     - &的作用:求地址运算符,p=&x;读法:把x的地址赋给p(指针)。 
     - \* 另外的用处:解引用。  解引用: x = \*p 把指针p指向的值赋值给x。  **即在等号的右侧不跟类型结合时,表示取其指向的值**。  char c = 'a'; char\* p = &a;  char c2 = \*p ; // c2此时是'a'.  现在,**`声明指针`、`取变量地址`给指针赋值、`取指针指向的值`三个操作都完成了**。  
     - 在c和旧式的c++代码(C++11之前)中,允许把字符串的字面值(双引号引起来的称为字面值)赋值给char\*
     - &在C++中还用作`引用`语法,后面详讲  
      
     
    ## 特殊的指针
     - void\* 指向未知类型的指针,有点java中Object的意思。但是它不允许解引用;不允许++递增操作。C++中也不能把(void\*)0赋值给int\*  
     - nullptr 空指针,不知想类你和对象的指针。取代以前的0NULL(是一个宏)  int\* i = 0;使用nullptr可读性更强,在当一组重载函数既可以接受指针也可以接受证书时,用nullptr可以避免歧义。  
     
    
    ## C++引用
    引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。**我理解成变量的别名**  
    引用很容易与指针混淆,它们之间有三个主要的不同:  
     - 不存在空引用。**引用必须连接到一块合法的内存**。
     - **一旦引用被初始化为一个对象,就不能被指向到另一个对象**。指针可以在任何时候指向到另一个对象。(所以一般引用前面有const)
     - 引用必须在创建时被初始化。指针可以在任何时间被初始化。 
     - 应用可以用作参数也可以用作返回值  
      
    示例:  
    ```cpp
    int i = 17;
    int& r = i;
    
    int test(const std::string& dbname){
    	cout << dbname << endl;
    	return 0;
    }
    
    double& test2(const int& i) {
    	double x = 1.0*i + 1.0;
    	double& t = x;
    	return t;
    }
    c++还分左值引用和有值引用。左值引用如上;右值引用是类似
    string&& xx = f1这种。