C/C++ 指针

        指针(pointer)在C类语言里是很重要的概念。类比的话,就像是你电脑桌面上的快捷方式,和文件实际所在的位置。指针指向了变量所在的地址

        当你声明一个变量的时候,计算机就会帮你分配一个空间储存它,为了确保之后你调用值的时候计算机都可以准确地找到它,这个空间会拥有一个唯一独特的编号,地址。指针是储存地址的变量(当然它被声明的时候,也会被分配一个地址[套娃!])。

声明指针:

声明一个指针用*:

int* ptr;
char* pptr;

        可以声明任何类型的指针(毕竟变量都需要储存,都有地址),指向指针的指针也可以(用两个**),指向数组也可以,指向结构体也可以。

引用:

        在C/C++里, 为了好记可以把引用和指针看成差不多的东西, 因为都和地址有关(其实不准确)。

int a = 1;
//引用
int &ref = a;
//指针
int *ptr = &a;

        对于引用来讲:

        ref 相当于 a 的别名(绰号,比如李红[a]小名叫小红[ref]),对 ref 的任何操作就是对a的操作。

        所以 ref 既不是a的拷贝,也不是指向 a 的指针,其实ref就是 a 它自己(声明ref并不会多开辟一块内存)。

引用的规则:

  • (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化,但指针最好也初始化,否则容易变成野指针)。
  • (2)不能有 NULL 引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。
  • (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

常用符号:

        说实话,我刚学的时候,* & ->这些符号老弄混

        在声明的时候:

int variable;
int* b;//*表示声明一个指针
int &c = variable;表示声明一个引用

        但在声明过后,符号意思会有些微变化:

int a = 1;
int* b;

b = &a;//此时&a是获取a的地址,赋值给b
cout << "都是值: " << *b << a << endl;
cout << "都是地址: " << b << &a << endl;
cout << "这是指针的地址: " << &b <<endl;

6899729de897492d83ecc0f9b2a54a38.png

        在代码内:*表示解引用符([]同样也是解引用哦,所以b[0]也可以打印出a的值{b[0]相当于*(b+0)})

        &成了取址符,获取变量的地址。

        (extra:->这个符号一般用在访问动态内存中的结构体数据)比如:

struct people {
    string name;
    int age;
};

int main(){
    people* FirstPerson = new people();//在堆里申请了一个结构体内存空间
    FirstPerson -> name = "Adam";//相当于(*FirstPerson).name = "Adam";
    FirstPerson -> age = 23;

    people SecondPerson;
    SecondPerson.name = "Bill";
    SecondPerson.age = 10;

    return 0;
}

        我在堆里申请了一块空间,计算机返回我了一个地址,我将它存到people* FirstPerson 这个指针里。而访问结构体成员,一般使用'.'访问符(比如SecondPerson.name)这样去访问它,所以'->'箭头符号等同于(*FirstPerson).name {先把指针解引用'*',再访问成员'.'}。

        总之,在代码里,常用的就是' * '和' & '

指针用在函数里:

        就是指函数传参,当指针作为参数传递时:

void PassPtr(int* a) {
    (*a)++;//记得是要对a指向的值做修改,不要写成a++
}

void PassVar(int b) {
    b++;
}

int main() {
    int x = 1;
    int y = 1;
    PassPtr(&x);
    PassVar(y);
    cout << x << " " << y << endl;

    return 0;
}

        函数传参进去的时候,都是拷贝了一份原数据进去的,只不过b拷贝的是值,a拷贝的是地址。之前说地址是独特的,对a解引用后,就可以对它指向的变量x直接做修改,而b只是对那个拷贝的值做了修改,也没有return出来,所以y是不会变的。

edf440fae7144f74969dcc07b8228fa2.png

        而如果你打印*a, b, x, y的地址也会看到,a=&(*a)=&x。

ac462129b44c4b309c6dbfc44a3e7688.png

        指针也能被函数返回:

int* func(int a) {
    a++;
    int c = a;
    return &c;
}

int* func1(int a) {
    a++;
    int* b = new int();
    return b;
}

再来两个函数,在返回指针时有一个特别要注意的点:

  • 如果返回的指针指向的变量是在函数内被创建的,要用动态内存

        以上两种函数,func没用,func1用了,可以看一下打印结果:

a9b514f6996a4fc2a218e24a0ae6e939.png

        func返回的指针里的变量,变成乱码了,而申请了堆内存的保存完好。

        这是因为:代码运行的时候,内存被分为四个区域:堆,栈,静态区,代码区。而main()调用的函数和local variable都会在栈(stack)中运行,运行完成后,自动收回内存(函数运行占的那部分被回收了!)

        在func里声明的变量c,虽然并不会立刻被抹除,但在运行其他函数时,可能会被占用从而把数据抹除掉(就像我运行了一个print),那么从函数传回来的指针被打印时,就会出现乱码了。

堆里的数据:

        就在刚才,我使用了动态内存 new了一个int *b。注意,动态内存申请的空间无法自动释放!需要手动去free一下。不过,在整个程序运行完后,计算机也会自动收回堆上的内存,但如果你使用了循环去不停的申请堆内存,却没有手动释放的话,代码会运行的越来越卡。还有一种情况就是,你在函数内申请完内存,但是忘了把地址传出来了,地址丢失,会造成内存泄露。

记得初始化

        避免你的指针变成野指针指到奇怪的地方,请务必初始化

int* ptr = NULL;//初始化指向NULL

        至少不要让程序一运行就报一些奇奇怪怪的错。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值