C/C++基础----指针

来源:互联网 发布:顶级域名绑定二级域名 编辑:程序博客网 时间:2024/06/08 07:01

1. 指针变量包含两个属性:指向的地址和地址所指向的内存里存储的数据类型。

和指针相关的易混淆的值有三个:指针的值(即指针指向的地址);指针本身的地址;指针指向的地址所存储的值。下面以图和代码说明:

复制代码
void Test_pointer(){         int test =123;     int *q = &test;     printf("&q指针本身的地址:%x\n",&q);     printf("q指指针指向的地址%x\n",q);     printf("*q指针指向地址所存的值:%x\n",*q);}int main(int argc,char* agrv[]) {         Test_pointer();    system("Pause");  } 
复制代码

上述输出如下:

指针变量本身就是一个地址值,前面加&表示取这个指针本身的地址,&q代表指针变量存储在哪,即它自身的内存地址;q代表指针指向的地址,相当于指针变量的值;*q即指针指向的地址存储的值。


2. int *p = NULL;与 int *p; *p=NULL 的区别。

   int *p = NULL表示定义一个整型指针变量,并把指针变量的变量值初始化为NULL,指针变量的值即指针所指向的地址置为NULL。

   int *p ; *p=NULL;同样定义一个整型指针,但是*p表示是指针指向地址所存储的值,即给p指向的内存赋值为NULL(这里可能会存在内存访问非法),可以这样写

 

    int a = 10int *p = &a;    *p = NULL;

结果就是 p所指向的地址即a的值变为了0。


3.指针和引用

首先我们来普及一下概念,说明一下什么是指针和引用,这里借用一下变量名作为过渡。

指针 ---- 指向某一块内存的变量,其本身存储的信息就是内存地址的首地址,其类型决定指向内存的大小。

比喻,超市的储物柜。我记住我放包的柜子在第一排右起第三个,这里的1-3就是一个地址,通过地址,我可以找到柜子。这里的地址就是一个指针。

变量 ---- 某一块内存地址数据值的名字

比喻,超市的储物柜。我记住我放包的柜子上有一张贴纸,上面写着18,通过18,我可以找到柜子。这里的18,就是变量名了。

引用 ---- 变量的别名

比喻,超市的储物柜。柜子的贴纸上面写着18,但是18不好记,我用谐音记忆法,把18想成“要发”,通过“要发”,也可以找到柜子。这里“要发”就是一个引用。

通过上面的比喻可以看出来,要找到柜子,有三种方法:

1. 第一排右起第三个                      地址(指针)

2. 柜子贴纸上号为18的                    变量名

3. “要发”                              引用


4. 示例:C++语言中,函数的参数和返回值的传递方式有三种:值传递、 指针传递和引用传递。

1)以下是“值传递”的示例程序。
由于Func1 函数体内的x 是外部变量n 的一份拷贝, 改变x 的值不会影响n, 所以n 的值仍然是0。

void Func1(int x) { <span style="white-space:pre"></span>x = x + 10; } int n = 0; Func1(n); cout << “n = ” << n << endl;// n = 0 

2)以下是“指针传递”的示例程序。
由于Func2 函数体内的x 是指向外部变量n 的指针,改变该指针的内容将导致n 的值改变,所以n 的值成为10。 

void Func2(int *x) { (* x) = (* x) + 10; } int n = 0; Func2(&n); cout << “n = ” << n << endl; // n = 10 
    3)以下是“引用传递”的示例程序。
由于Func3 函数体内的x 是外部变量n 的引用,x 和n 是同一个东西,改变x 等于改变n,所以n 的值成为10。

void Func3(int &x) { x = x + 10; } int n = 0; Func3(n); cout << “n = ” << n << endl; // n = 10 



4. 例子:

这里以经典的值交换为例,来说明int、int*、int&、int*&、int&*、int**。

1、int

#include <iostream>     using namespace std;               void swap1(int a, int b){         int tmp;         tmp = a;         a = b;         b = tmp;     }     int main(){         int a = 1;         int b = 2;         swap1(a, b);         cout<<"a = "<<a<<endl;         cout<<"b = "<<b<<endl;         system("pause");         return 0;     }

交换失败。基础牢靠的同学一眼就看出来,这样的交换只是交换了形参的值,是无法达到交换值的效果的,这段程序很简单,不做细说。

2、int*

void swap2(int *a, int *b){        int tmp;        tmp = *a;        *a = *b;        *b = tmp;    }    int main(){        int a = 1;        int b = 2;        swap2(&a, &b);        cout<<"a = "<<a<<endl;        cout<<"b = "<<b<<endl;        system("pause");        return 0;    }
交换成功。上面是的swap2接受的参数是地址,我们传入地址,就可以直接操作实参的值了,这个也很简单,不做细说。

3、int&

void swap3(int& a, int& b){        int tmp;        tmp = a;        a = b;        b = tmp;    }    int main(){        int a = 1;        int b = 2;        swap3(a, b);                cout<<"a = "<<a<<endl;        cout<<"b = "<<b<<endl;        system("pause");        return 0;    }
交换成功。引用即别名,通过引用也是可以直接访问到实参和控制实参的,这里不做细说。

4、int*&

#include <iostream>     using namespace std;         void swap5(int *&a, int *&b){         int tem = *a;         *a = *b;         *b = tem;     }          int main(){         int a = 1;         int b = 2;                   int *aPtr = &a;         int *bPtr = &b;         int *&arPtr = aPtr;         int *&brPtr = bPtr;                   swap5(arPtr, brPtr);                   cout<<"a = "<<a<<endl;         cout<<"b = "<<b<<endl;         system("pause");         return 0;     }

交换成功。这个稍微复杂一点,int*&  value这样一个声明,我们从最接近value的符号看起,是个&,说明value是一个引用,它是一个什么引用呢?再看*,它是一个指针的引用,即指针的别名,我们用*value就可以访问到实参的值了。所以,其交换函数的内部逻辑跟int *是一样的。

5、int&*

这样定义就不合法,如果从字面上来看,我们分析一下,如int &* value,最接近value的是*,说明value是一个指针,再看前面的是&,说明是一个指针的引用,而指针是无法被引用的,所以,这样的定义是不合法的,不要记这个。

6、int**

 void swap6(int **a, int **b){         int tmp;         tmp = **a;         **a = **b;         **b = tmp;     }     int main(){         int a = 1;         int b = 2;         int *aPtr = &a;//指向数据的指针         int *bPtr = &b;//指向数据的指针         int **aaPtr = &aPtr;//指向指针的地址的指针         int **bbPtr = &bPtr;//指向指针的地址的指针         swap4(aaPtr, bbPtr);         cout<<"a = "<<a<<endl;         cout<<"b = "<<b<<endl;         system("pause");         return 0;     }
交换成功。同样的,比如int **value, 最接近value的是*,说明value是一个指针,在前一个是*,说明是一个指向指针的指针,这样是合法的,那么如何访问value代表的实际参数的值呢?很简单,用**value就可以了,记住*是一个操作符,如同&一样,不过&是取地址操作符,而*是取值操作符。




6. 最后,总结一下指针和引用的相同点和不同点:

相同点:

都是地址的概念;指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
    不同点:
1、指针是一个实体,而引用仅是个别名;
2、引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
3、引用没有const,指针有const,const的指针不可变;
4、引用不能为空,指针可以为空;
5、“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
6、指针和引用的自增(++)运算意义不一样;
7、引用是类型安全的,而指针不是 (引用比指针多了类型检查)


对比上述三个示例程序,会发现“引用传递”的性质象“指针传递”,而书写方式象 
“值传递”。实际上“引用”可以做的任何事情“指针”也都能够做,为什么还要“引用” 
这东西? 
答案是“用适当的工具做恰如其分的工作”。 
指针能够毫无约束地操作内存中的如何东西,尽管指针功能强大,但是非常危险。 就象一把刀,它可以用来砍树、裁纸、修指甲、理发等等,谁敢这样用? 如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”, 以免发生意外。比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如 果把取公章的钥匙交给他,那么他就获得了不该有的权利。 


0 0