ENFP-T型人格患者|

_Youngxy

园龄:3年7个月粉丝:5关注:28

c++ 浅谈指针

指针

绝大部分参考自C++指针

概念

指针是“指向(point to)”另外一种类型的复合类型

复合类型是指基于其它类型定义的类型。

指针的值实质是内存单元(即字节)的编号

有时你申请一个变量(如int x;),计算机就会随机给你分配一个空间,你可以在那个空间内改变数值

就像计算机给了一个叫做a的小房子,但是只能在里面放int类型的值

比如你输入x=-1,计算机首先会把小房子找到,然后把-1放在里面

(如果里面有其他值,就拿出来)

那这个小房子的地方在哪里呢,就存放在地址里

每一个变量都有一个地址(即是它在内存中的位置)

所谓指针就是一个箭头→,指向一个地址,然后这个地址里有一个值

声明

在类型后加上星号(*)即可,当然指针也分类型的,即:

int* a;//一个指向int类型房子的指针a(当前还是随机值)
char* b;//一个指向char类型房子的指针b

如果你不知道类型,也可以用void* c;

int* a,b;

有些人要问了,如果写成上面那种形式的话,那a,b各是什么类型呢?

答案是a是int类型指针,b是int类型的普通变量。

所以通常申请指针这样写:

int *a,*b;

注意定义指针后指针会指向一个随机的位置

如果你对这个位置进行不正确的操作,就有可能发生内存错误

操作

赋值

首先我们要学习一个取地址运算符&,它可以获取变量的地址

有些小伙伴或许并不陌生了,因为我们平常输入的时候都会用到它:

scanf("%d",&x);

这个句子的意思就是找到x所在的地址,然后把输出的int值放在里面

甚至可以输出一个地址,用printf和格式控制符,或者也可以用cout输出,这两种是可以等价替换的

如:

int a;
printf("%p\n",&a);
cout<<&a<<endl;

运行结果:

00000000007bfe1c0x7bfe1c
00000000007bfe1c0x7bfe1c

输出

*a表示a指向的值。

#include<bits/stdc++.h>
using namespace std; 
int main(){
	int b;
	int *a=&b;
    *a=0;
    printf("执行 *a=0 后,\n");
    printf("指针的地址:  %p\n",&a);
    printf("指针指向的值: %d\n\n",*a);
    *a=1000;
    printf("执行 *a=1000 后,\n");
    printf("指针的地址:  %p\n",&a);
    printf("指针指向的值: %d\n\n",*a);
    //&a=1000的写法是错误的
    return 0;
}

运行结果:

执行 *a=0 后,
指针的地址:  000000000067fe10
指针指向的值: 0

执行 *a=1000 后,
指针的地址:  000000000067fe10
指针指向的值: 1000


可以发现指针的地址并没有改变000000000067fe10

因为我们改变的是指针指向的地址所存的值

所以用*a其实表示的是b

加减操作

指针可不可以进行加减操作呢,我试了一下,答案是可以的

其实想起来很简单,把地址前移或后退一段地址,是可以的

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a=0,*b;
    b=&a;
    printf("指针指向的地址:  %p\n\n",b);
    b=b+1;
    printf("指针指向的地址:  %p\n\n",b);
    printf("a的值:  %d\n",a);
    return 0;
}

运行结果:

指针指向的地址:  00000000007bfe14

指针指向的地址:  00000000007bfe18

a的值:  0

因为b指向的是一个int类型,这里就是相当于把b的地址后移一个int类型,就是4

所以我们结果看到的是00000000007bfe18,而不是00000000007bfe15

指针指向地址的变化是不会改变原地址所存值的

所以a的值还是0

同理:

#include<bits/stdc++.h>
using namespace std;
int main(){
    bool a,*b;
    b=&a;
    printf("指针指向的地址:  %p\n\n",b);
    b++;
    printf("指针指向的地址:  %p\n\n",b);
    return 0;
}

运行结果:

指针指向的地址:  000000000067fe17

指针指向的地址:  000000000067fe18


bool类型大小为1,于是地址加1

数组

以前我们操作通常都是酱紫:

#include<bits/stdc++.h>
using namespace std;
int n,a[102];
int main(){
    printf("输入:\n");
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    printf("-------------------------\n");
    printf("输出:\n");
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}

学了指针,可以酱紫:

#include<bits/stdc++.h>
using namespace std;
int n,a[100];
int main(){
    printf("输入:\n");
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",a+i);
    printf("-------------------------\n");
    printf("输出:\n");
    for(int i=1;i<=n;i++)
        printf("%d ",*(a+i));
    return 0;
}

运行结果:

输入:
2 
1 2
-------------------------
输出:
1 2

指针应用

指针与数组

我们知道,当定义数组int a[10];时,系统会连续开10个空间,所以:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[10]={1,2,3,4,5,6,7,8,9,10};
    int *p;
    for(p=&a[0];p<&a[0]+10;p++)
        printf("%d ",*p);
    return 0;
}

当运行到第一次for循环是,p指针指向a[0]的地址00000000007bfdf01,其指向的值就是1

重点&a[0]+10是什么意思?

就是a[0]的地址后移10位的地址,所以p小于&a[0]+10

本质上就相当于最初的输出的方法

其中a[0]也可以换做a

也就是数组的首地址

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[10]={100,200,300,400,500,600,700,800,900,1000};
    printf("%d\n",*a);
    printf("%d\n",*a+5);
    printf("%d\n",*(a+5));//这条语句与上条有区别
    return 0;
}

运行结果:

100
105
600

其中*a+5*(a+5)的意义不同

  • *a+5的意思是a指向的值加5,所以得到的是100+5=105
  • *(a+5)的意思是a的地址加5,也就是&a[5],指向的值是600

指针与函数

有时指针可以看成一个数组

如:

#include<bits/stdc++.h>
using namespace std;
int n;
int sum(int *A){
    int _sum=0;
    for(int i=1;i<=n;i++)
        _sum+=A[i];
    return _sum;
}
int main(){
    int A[100];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    printf("%d",sum(A));
    return 0;
}

运行结果:

3 
1 2 3
6

函数指针

函数指针甚至还可以指向函数,但指针的参数要和原函数一样。

注意:函数指针必须加上括号,否则系统会以为你定义了一个int类型的指针

于是:

#include<bits/stdc++.h>
using namespace std;
int n;
int (*p)(int*);//这里是函数指针
//int *p(int*);//不能这样写
int sum(int *A){
    int _sum=0;
    for(int i=1;i<=n;i++)
        _sum+=A[i];
    return _sum;
}
int main(){
    int A[100];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    p=sum;
    printf("%d",p(A));
    //也可以这样写:
    //printf("%d",(*p)(A));
    return 0;
}

运行结果:

3
1 2 3 
6

不难发现:

    p=sum;
    printf("%d",p(A));

这一段是等于:

	printf("%d",sum(A));

所以,这里的指针是指向的一个函数看上去好像没啥用

结构体指针

声明结构体指针就直接在名称前加*即可,指向结构体成员有两种方法,以程序为例

#include<bits/stdc++.h>
using namespace std;
struct node{
    int a,b;
}x,*y;
int main(){
    y=&x;//y存的是x的地址
    x.a=123;
    x.b=987;
    printf("%d\n",(*y).a);//第一种写法,一定要加括号
    printf("%d\n",y->b);//第二种写法,不要加*号
    return 0;
}

运行结果:

123
987

双重指针

双重指针指向的是某个指针的地址

如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a=100,*b,**c;
    b=&a;c=&b;
    printf("%p %p %p %p\n",&a,b,*c,&c);
    printf("%d %d %d\n",a,*b,**c);
    return 0;
}

运行结果:

000000000067fe1c 000000000067fe1c 000000000067fe1c 000000000067fe08
100 100 100

完结撒花❀

★,°:.☆( ̄▽ ̄)/$:.°★

本文作者:Yvette的博客

本文链接:https://www.cnblogs.com/yvette1217/p/16218701.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Youngxy  阅读(81)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示