2021年信息学部物联网工程学院学生科协第二次软件大培训

一、指针是什么

1、地址

  • 定义:C语言地址,是指内存地址的概念。计算机内存中的各个存储单元都是有序的,按字节编码。此编码即为地址。

  • 通俗解释:地址就是可以唯一标识某一点的一个编号,即一个数字。内存像尺子一样线性排布,为了计算机可以在众多内存当中找到,科学家引入了地址的概念,计算机则可以通过地址来寻找到需要的那一块内存。就像通过门牌号的指引来访问到真正的住户,在这里,门牌号代表地址,住户则代表真正的内存内容。

2、指针

  • 定义:狭义的指针定义实际上就是刚刚所讲述的地址,但是我们习惯上将指针变量也叫做指针,而指针变量相当于是值类型为地址的变量。

  • 通俗解释:指针是一种数据类型,就像int、float一样,int类型装载整型数据,float类型装载浮点型数据。而指针则是装地址型数据,仅此而已。习惯上我们也将“指针变量”简称为“指针”,但大家心里一定要明白这两个指针的区别。一个是真正的指针,它的本质是地址;而另一个是指针变量的简称

  • 图片讲解指针含义:

    在这里插入图片描述

二、指针的简单使用

1、两个运算符&和*

&a的运算结果是一个指针,指针的类型是a 的类型加个*,指针所指向的类型是a 的类型,指针所指向的地址就是a 的地址。*p的运算结果就五花八门了。总之*p的结果是p所指向的东西。换句话说,一个指针指向一个变量,*这个指针就是这个变量本身。另外,int *当中的星号不是运算符,而是和int看成一个整体,int *是一种数据类型

2、实战演练

定义一个指针变量:

int *a;     //定义整型指针变量a
char *b;    //定义char类型指针变量
int **c;    //定义(int *)类型指针变量,所谓的二级指针
char ***d;  //定义(char **)类型的指针变量,所谓的三级指针

指针变量的赋值:

int x = 5;
int *p = &x;
printf("%d\n", *p);
//或者
int i, j, *p, *q;
p = &i;
q = &j;
i = 2;
j = 3;

3、指针的特殊赋值方式

指针变量的值中有一个非常特殊的值: NULL,它不指向系统中的任何变量或者函数。一般,我们使用它作为一个标志(返回指针的函数没有正确执行、到达链表末尾等等)访问NULL指针,实际上就是访问0x0地址,由于没有权限访问,因此系统会报错。

4、悬摆指针的危害

如果指针没有指向任何变量,即没有赋值或初始化,那么这个指针就是一个悬摆指针它可能指向内存中的任意一个位置,这就导致了后面给他赋值可能会篡改指针原来指向的那个值,随意访问或操作悬摆指针,轻则出现程序运行时错误,重则导致系统崩溃。

5、实例感受指针的加减

int a = 10, *pa = &a, *paa = &a;
double b = 99.9, *pb = &b;
char c = '@', *pc = &c;
printf("&a=%#X, &b=%#X, &c=%#X", &a, &b, &c);
printf("pa=%#X, pb=%#X, pc=%#X", pa, pb, pc);
pa++;pb++;pc++;
printf("pa=%#X, pb=%#X, pc=%#X", pa, pb, pc);
pa-=2;pb-=2;pc-=2;
printf("pa=%#X, pb=%#X, pc=%#X", pa, pb, pc);
if(pa == paa){
	printf("%d\n", *paa);
}else{
	printf("%d\n", *pa);
}

运行结果

&a=0X28FF44, &b=0X28FF30, &c=0X28FF2B
pa=0X28FF44, pb=0X28FF30, pc=0X28FF2B
pa=0X28FF48, pb=0X28FF38, pc=0X28FF2C
pa=0X28FF40, pb=0X28FF28, pc=0X28FF2A
2686784

6、指针的加减运算

从运算结果可以看出:pa、pb、pc 每次加 1,它们的地址分别增加 4、8、1,正好是 int、double、char 类型的长度。以pa为例子,实际上地址值加了sizeof(int) 这么多。说明白点,我们加减的数字是以指针指向的数据类型为量度的,p+1表示p在内存中前移1个int的距离,如果p不是int类型,而是其他类型道理也是一样。

7、图解指针运算

在这里插入图片描述

三、指针与数组

1、指针数组

  • 定义:存储指针的数组我们把它称为指针数组。

  • 案例演示:通过指针输出a,b,c

    #include <stdio.h>
    int main() {
        int a = 16, b = 932, c = 10;
        int *arr[3] = {&a, &b, &c};
        printf("%d,%d,%d", *arr[0], *arr[1], *arr[2]);
        return 0;
    }
    
  • 图解指针数组的元素:

    在这里插入图片描述

  • 从优先级的角度理解指针数组:

    在这里插入图片描述

    从该图中可知:数组取下标的优先级为1,即数组名与数组取下标先行结合。

    图示如下:

    在这里插入图片描述

2、一维数组与指针

  • 一维数组数组名本质上指向这个数组第一个元素的指针。

    代码验证:

    printf("%d\n",x);
    printf("%d\n",&x[0]);
    

    运行一下你会发现输出的两行是一样的。

  • 案例演示:使用指针遍历一维数组。

    #include <stdio.h>
    int main() {
        int x[] = {99, 15, 100, 88, 252};
        int *p = x;
        int i;
        for (i = 0; i < 5; i++) {
            printf("%d ", *(p + i));
        }
        return 0;
    }
    
    

运行过程如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、二维数组与指针

  • 行指针、列指针与数组名的定义
    行指针:指向一整行的地址,不指向具体元素的地址的指针。
    列指针:指向具体元素的地址的指针。
    数组名:数组名指向该数组的第一个元素的首地址。

  • 案例说明:

    int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};
    

    演示代码中a为数组名,a[0]、a[1]、a[2]为行指针,具体元素的地址为列指针。
    具体图示如下:

在这里插入图片描述

a[0]表示的是第0行第0个元素的地址
a[1]表示的是第1行第0个元素的地址
a[2]表示的是第2行第0个元素的地址

*a[0]表示的是第0行第0个元素的值
*a[1]表示的是第1行第0个元素的值
*a[2]表示的是第2行第0个元素的值

下面为等价的表达式,均表示第1行第0个元素的值

*a[1]   *(*(a+1))   **(a+1)
  • 以下为二维数组与指针的总结

    在这里插入图片描述

4、数组指针

  • 如果要将一个指针指向一个多维数组,我们就要用到数组指针。

  • 案例演示:用一个数组指针来遍历二维数组

    #include <stdio.h>
    int main() {
        int x[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};
        int (*p)[4] = x;
        int i, j;
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 4; j++) {
                printf("%d\t", *(*(p + i) + j));
            }
            printf("\n");
        }
        return 0;
    } 
    
  • 从优先级角度理解指针数组

在这里插入图片描述

下面图示为p和*p的指向:

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值