CPP_4_简单到极致的指针

极度空间

张一极

201994

程序的第一步就是写入内存,内存作为连续的地址,不同机器储存方式不一样,不详细说,我们要认为所有机器的内存地址从0开始,一直到机器内存上限:

#include

using namespace std;

int i_,i__,i___;

int main(){

cout<<"i__ : "<<(long)&i__<<endl;

cout<<"i___ : "<<(long)&i___<<endl;

}

通过地址输出给出地址:

➜code g++ i.cpp -o i

➜code ./i

i__ : 4435849452

i___ : 4435849456

可以看出,这里的地址有一个有趣现象,我们在main里面定义一个变量试试:

#include
using namespace std;

int i_,i__,i___;

int main(){

int i_____,i;

cout<<"i______ :"<<(long)&i_____<<endl;

cout<<"i :"<<(long)&i<<endl;

cout<<"i__ : "<<(long)&i__<<endl;

cout<<"i___ : "<<(long)&i___<<endl;

}

code ./i

i______ :140732825254044

i :140732825254040

i__ : 4390478060

i___ : 4390478064

可以看出,main里面的变量地址相近,差距是一个int4个字节,main以外的变量,使用不同区域的地址,分配内存的机制了解以后,我们可以通过这个机制,学会指针的使用,指针本质也是一个变量,用于保存地址而已,一个指针的定义:

int* arr ;

但是不可以同时使用

int* arr1,arr2 ;

这样的情况下,只有arr1是指针变量,而剩下的是普通int类型,cpp中只能每行定义一个指针,c++一般在定义的时候就执行初始化,所以一般我们定义了指针变量,会给一个初值:

int i___ = 2;

int* arr1 = &i___;

这就表示了,arr储存的是i___的值,知道了保存,我们看一下怎么读取指针变量里面的值,或者说指向的值,同样简单到极致:

#include

using namespace std;

int i_,i__,i___;

int main(){

    

    int i_____=10,i;

    int* arr_i = &i_____;

    *arr_i = 10000000;

    cout<<“i______ :”<<(long)*arr_i<<endl;

    cout<<“i :”<<(long)&i<<endl;

    cout<<“i__ : “<<(long)&i__<<endl;

    cout<<“i___ : “<<(long)&i___<<endl;

}

  code g++ i.cpp -o i

  code ./i

i______ :10000000

i :140732717848728

i__ : 4497883372

i___ : 4497883376

接下来介绍一个概念,函数的按值传递,python中函数直接进行复制并且传入函数领域,python底层的cpp,这个方式叫做按值传递:

#include

using namespace std;

void j_(int j){

    cout<<“j = “<<j<<endl;

    j = 10;

    cout<<“j = “<<j<<endl;

}

int main()

{

    int j__ = 1;

    cout<<“j__ = “<<j__<<endl;

    j_(j__);

    cout<<“j__ = “<<j__<<endl;

    return 0;

}

在函数j_j的值是通过函数参数按值传递进去的,而在主函数里面,j__的值为1,初始值传入以后,是的j_里面的j也为1,然后在函数体里,赋值j=10;进而j的值就改变为10,但是j__的值并没有改变.

  code g++ j.cpp -o j

  code ./j

j__ = 1

j = 1

j = 10

j__ = 1

可以看出,外部对象也就是传入的参数j__,他的值并没有被改变,因为他和j的储存地址是不一样的,而我们如果要在函数里改变外部对象的值,就需要定位到j__的地址,并且改变他的值,这时候用指针就轻而易举了:

#include

using namespace std;

void j_(int* j){

    cout<<“j = “<<j<<endl;

    cout<<“j = “<<*j<<endl;

    *j = 10;

    cout<<“j = “<<j<<endl;

}

int main()

{

    int j__ = 1;

    cout<<“j__ = “<<j__<<endl;

    cout<<“j__add = “<<&j__<<endl;

    j_(&j__);

    cout<<“j__ = “<<j__<<endl;

    return 0;

}

首先,主函数里,定义了一个int类型的1,打印一下j__的值,方便确认,而后,我们使用&取得他的地址,方便核对,后续执行j_函数,j_函数体里,传入了指针变量j,打印了j的地址,接着打印传入的j的值,然后取j地址的值赋值为10,再次打印j的地址确保不变,跳出函数体后,打印j__的值发现,变成了函数里面给*j赋的值.

结果:

  code g++ j.cpp -o j

  code ./j

j__ = 1

j__add = 0x7ffeeef74898

j = 0x7ffeeef74898

j = 1

j = 0x7ffeeef74898

j__ = 10

  code

cc++,指针的作用几乎一致,c++多了一种按引用传递的方式,这是一种让语法更清晰的传递方式:

#include

using namespace std;

void j_(int &j){

    cout<<“j = “<<j<<endl;

    cout<<“j = “<<&j<<endl;

    j = 10;

    cout<<“j = “<<j<<endl;

}

int main()

{

    int j__ = 1;

    cout<<“j__ = “<<j__<<endl;

    cout<<“j__add = “<<&j__<<endl;

    j_(j__);

    cout<<“j__ = “<<j__<<endl;

    return 0;

}

唯一的不同在于程序的函数入口,变成了一个取地址符号,表示传入地址以后j代表这个数据,j赋值以后同样能够影响到外围变量,具体需要自己实验去理解.

  code g++ k.cpp -o k

  code ./k

j__ = 1

j__add = 0x7ffedff3e898

j = 1

j = 0x7ffedff3e898

j = 10

j__ = 10

  code

j__的参数看起来是值传递,而其实是地址的传递,实际上传入的值会被&获取地址然后给到函数里面,j__地址赋值,实际上是对j__实际的地址代表的值赋值.

还理解不来?

给一个更简单的例子:

#include

using namespace std;

void l(int &m){

    m = 2;

    cout<<m<<endl;

}

int main(){

    int l_ = 1;

    l(l_);

    cout<<l_<<endl;

}

上述代码中,传入的事l_没错,但是到了函数参数里面,就变成了获取l_的地址,然后赋值,对应的,给指针赋值,就是给指针对应的数据复制,两个储存空间是同样的,位置一样,所以这个就是指针带来的便利,方便的指向我们需要的东西.

下一个样例 :定义一个指针,间接引用给函数,更深刻理解指针工作原理:

#include

using namespace std;

void l(int &m){

    m = 2;

    cout<<m<<endl;

}

int main(){

    int l_ = 1;

    int* p = &l_;

    l(*p);

    cout<<l_<<endl;

}

结果相同的事,*p作为l_的地址,传递进去以后,依旧代表着l_.不用多说的是int的指针只能获取int类型的地址.

Amazing

此条目发表在ALL, CPP分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注