C++指针详解

指针是啥

众所周知,你在程序中向计算机申请一个变量(如int a),计算机会分配给你的变量一个空间。用int a举例子,计算机就给你了一个名叫a的房子,只能在里面放int类型的值。当然,你可以直接写a=10,这样计算机会帮你找到名叫a的房子,把10放进去。
那么这个房子在哪呢?就有了地址,每个变量都会有一个地址(即它在内存中的位置),指针,便是一根棍子,指着这个位置,指针里存的就是这个地址。

怎么用

声明

在类型后面加上*即可,当然指针也是分类型的,如:

int* p;//一个指向(还没确定指向哪里)int类型房子的指针p
double* k;//指向double的k

如果你不确定这个类型,可以用void:

void* p;

但是,你如果这样写:

int* p,q;

事实上你是定义了一个指针和一个普通变量,所以我通常这样写:

int *p,*q;

注意定义指针后指针会指向一个随机的位置,如果你对这个位置进行操作,就有可能发生内存错误。

操作

存入地址

这里需要用到一个新运算符:&,它称为取地址符,用于获取一个变量的地址。
例如:

int *p;
int a;
p=&a;

你应该发现,scanf后面如果输入一个变量要用&,所以scanf后面的参数就是一个地址。
你甚至可以输出一个地址,如果用cout就直接输出p即可,用printf需要用到格式控制符%p,如:

int a;
scanf("%d",&a);
printf("%p",&a);

每个电脑上的结果可能会不一样,例如我的:

输出该地址上的值

如果你想知道指针所指向位置的值,需要再次用到*

int *p;
int a;
p=&a;
a=10;
printf("%d\n",*p);
a=15;
printf("%d\n",*p);

运行结果是什么呢?
这里写图片描述
不难理解,因为一个变量的地址永远不会变。

加/减

你可能会想,指针是不是也有+,-操作呢?答案是肯定的,但不是把这个位置的值+,-,而是把地址往后或往前移动。
可以做一个实验:

#include<cstdio>
int main()
{
    int a=1,*p,*q;
    p=&a;
    q=p+1;
    printf("%p %p",p,q);
}

结果:这里写图片描述
为什么多了4呢?因为int类型是4个字节,所以加int类型的1会往后移4个字节。
到这里很想问了,那加char类型的'1'会怎么样?

#include<cstdio>
int main()
{
    int a=1,*p,*q;
    p=&a;
    q=p+'1';
    printf("%p %p",p,q);
}

结果:

并不是只移了1位,因为这里的指针q是int类型的,你的'1'被自动转为了ASCII码,所以后移了很多位。
应该这样做:

#include<cstdio>
int main()
{
    char a='1',*p,*q;
    p=&a;
    q=p+1;
    printf("%p %p",p,q);
}

这里的+1就成了char的后移一位,也就是1个字节,结果:

指针数组

很好理解:

int *p[10];

声明一个有十个指针(p[0],p[1],p[2],…,p[9])的数组,每个元素都是一个指针。

其他

scanf

要输入n(n≤1000000)个数存入a数组再输出,一般我们会这样写:

#include<cstdio>
#define MAXN 1000000
int a[MAXN+5],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
}

知道了指针,我们有了更装逼的方法:

#include<cstdio>
#define MAXN 1000000
int a[MAXN+5],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",a+i);
    for(int i=1;i<=n;i++)
        printf("%d ",*(a+i));
}

结果:

指针与其他数据结构

指针与数组

我们知道,当int a[10]时,系统会连续开10个空间,所以我们可以这样访问数组的元素:

#include<cstdio>
int main()
{
    int a[10]={0,2,4,6,8,10,12,14,16,18};
    int *p;
    for(p=&a[0];p<&a[0]+10;p++)
        printf("%d ",*p);
}

结果就不截图了。
其中有一个:p<&a[0]+10是什么意思呢?
不难理解,10是数组的大小,&a[0]是数组的首地址,&a[0]+10就是数组末尾地址的下一位
这里的p还有一个名称,叫做数组的迭代器,我们不说这些东西。
其实获取数组首地址还有一个办法,直接这样:

int a[10];
int *p;
p=a;

这样就可以了,事实上,数组你可以看成一个指针,可以这样写:

#include<cstdio>
int a[10]={0,2,4,6,8,10,12,14,16,18};
int main()
{
    int *p;
    p=a;
    printf("%d\n",*a);
    printf("%d\n",*(a+5));//注意加括号,否则就是输出“a指向的值加5”了
    printf("%d\n",*p);
    printf("%d\n",*(++p));
}

结果:

相反的,指针也可以看做一个数组,所以经常有这样写的:

int sum(int *a,int n)
{
    int ans=0;
    for(int i=1;i<=n;i++)
        ans+=a[i];
    return ans;
}

那么可以这样用:

#include<cstdio>
int sum(int *a,int n)
{
    int ans=0;
    for(int i=1;i<=n;i++)
        ans+=a[i];
    return ans;
}
int main()
{
    int A[10],n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    printf("%d\n",sum(A,n));
}

结果:

函数指针

你需要知道,在一个程序中,不仅仅是变量需要分配内存,函数也一样,那么函数自然也可以有指针,是函数的入口地址。函数指针声明只比函数声明多一个*一对括号,例如:

int (*Psum)(int*,int)

其中吧*Psum括起来的括号一定不能少,不然编译器会认为你声明了一个叫Psum的函数,返回类型是int*。
也就是说可以这样用:

#include<cstdio>
int (*Psum)(int*,int);
int sum(int *a,int n)
{
    int ans=0;
    for(int i=1;i<=n;i++)
        ans+=a[i];
    return ans;
}
int main()
{
    int A[10],n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);
    Psum=sum;//不用'&',因为这里函数没有括号视为是函数的地址
    printf("%d\n",(*Psum)(A,n));
}

到了这里,我们就知道sort是如何把函数作为函数的参数的了,可以拟出一个sort(只针对int数组):

void sort(int *begin,int *end,bool (*cmp)(int,int))
{
    /*......*/
}

结构体指针

关于结构体,请看:C++重载运算符详解
和声明一般指针一样,名称前加*即可。
要访问这个指针所指向结构体当中的元素有2种方法:
1.’*’法:在指针前加上*,再把它们括起来,就可以当该指针指向的结构体用了。
2.’->’法,和一般结构体用法一样,只是把成员运算符.变为->即可。
详见示例:

#include<cstdio>
struct student
{
    int snum;
    int age,grade;
};
student T;
student *p;
int main()
{
    p=&T;
    T.snum=15;
    T.age=12;
    T.grade=90;
    printf("%d\n",(*p).snum);
    printf("%d\n",p->age);
    printf("%d\n",T.grade);
}

结果:

多重指针

和数组一样,你可以在声明时连续打2个(或多个)*,例如:

#include<cstdio>
int main()
{
    int **p,*q;//p就是指向一个指针的指针,q是指向一个普通变量的指针
    int a;
    a=1;
    q=&a;
    p=&q;
    printf("%p  %p  %p  %p\n",p,*p,q,&a);
    printf("%d  %d  %d",**p,*q,a);
}

猜猜结果:
这里写图片描述
前面的地址有可能会不一样,但输出的格式肯定是:
Q P P
A A A
为什么*p要用%p输出?因为*pq,而q是一个指针,所以用%p

  • 64
    点赞
  • 143
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值