C语言进阶——指针详解

目录

一、指针引入

二、计组相关知识补充

三、指针变量详解

3.1指针变量的创建

3.2指针相关操作符

3.3指针变量的理解

3.4指针变量的大小

3.5指针类型的意义

3.6泛型指针void*

3.7const修饰指针

四、指针的运算

五、指针与数组

5.1数组名的理解

5.2⼀维数组传参的本质

5.3二维数组传参的本质

5.4指针数组

5.5数组指针

六、指针与函数

6.1函数指针变量

6.2函数指针的使用


一、指针引入

写⼀个函数,交换两个整型变量的值(经典问题)

#include <stdio.h>
void swap(int x, int y)
{
     int temp = x;
     x = y;
     y = temp;
}

int main()
{
     int a = 0;
     int b = 0;
     scanf("%d %d", &a, &b);
     printf("交换前:a=%d b=%d\n", a, b);
     swap(a, b);
     printf("交换后:a=%d b=%d\n", a, b);
     return 0;
}

这是初学者常会遇到的问题,究其原因就是在函数调用时,形式参数仅仅是实际参数的一份拷贝,无法影响到实际参数的值。若要修改,就要用到本文下面讲的指针相关知识。 

二、计组相关知识补充

        如果把一个存储体看作一幢大楼,那么每个存储单元可看作大楼中的每个房间,每个存储元可看作每个房间中的一张床位,床位有人相当于 “1” ,无人相当于 “0” 。床位数相当于存储字长。显然,每个房间都需要有一个房间编号,同样可以赋予每个存储单元一个编号,称为存储单元的地址号。主存的工作方式就是按存储单元的地址号来实现对存储字各位的存(写入)、取(读出)。这种存取方式称为按地址存取方式,即按地址访间存储器(简称访存)。

图片来源:计算机组成原理第三版(唐朔飞)

C语⾔中给地址起了新的名字叫:指针

三、指针变量详解

3.1指针变量的创建

#include <stdio.h>
int main()
{
 int a = 10;
 int* pa = &a;    //取出a的地址存储到指针变量pa中
 return 0;
}

3.2指针相关操作符

  1. 取地址操作符&: 取出变量的地址
    #include <stdio.h>
    int main()
    {
      int a = 10;
      printf("%p\n", &a);
      return 0;
    }
    
  2. 解引⽤操作符*:将地址转为它指向的数据
    #include<stdio.h>
    int main()
    {
      int a = 100;
      int* pa = &a;
      *pa = 0;    //修改a的值为0
      return 0;
    }

3.3指针变量的理解

int * pa = &a

  1. * :说明是指针变量
  2. pa:变量名
  3. int :指针指向数据(此处为a)的类型
  4. 指针自身也是变量,也有属于自己的地址

3.4指针变量的大小

  • 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节。
  • 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节。
  • 指针变量的⼤⼩和类型是⽆关的,只与平台位数有关。

3.5指针类型的意义

        指针变量的⼤⼩和类型⽆关,相信读者会有这样的疑问:为什么还要存在指针类型呢?

  • 决定了每次访问数据的字节数:int-4, double/float-8, char-1
#include<stdio.h>
int main()
{
    int arr[] = { 1,2,3,4 };
    short* p = (short*)arr;
    for (int i = 0; i < 4; i++)
    {
        *(p + i) = 0;
    }
    for (int i = 0; i < 4; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

分析:short类型的指针决定了指针每次只能访问2个字节,而int类型为4个字节。也就意味着两次通过指针修改才可以改动一个整型的值。所以最后结果仅仅改变了两个数组元素的值。

  • 决定了指针加减整数的步长:int-4, double/float-8, char-1
int main()
{
    int n = 10;
    char* p1 = (char*)&n;
    int* p2 = &n;
    printf("%p\n", &n);
    printf("%p\n", p1);
    printf("%p\n", p1 + 1);
    printf("%p\n", p2);
    printf("%p\n", p2 + 1);
    return 0;
}

 分析:指针的类型决定了指针向前或者向后的步长

3.6泛型指针void*

  1. 这种类型的指针可以⽤来接受任意类型地址
  2. 缺陷是:无法进行指针加减整数运算,无法解引用操作

3.7const修饰指针

  1. const如果放在*的左边:修饰的是指针指向的内容(即为指向变量的值),保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。
    int a = 10;
    int b = 10;
    const int* p = &a;
    
    *p = 0;//错误,无法修改
    p = &b;//可以
  2. const如果放在*的右边:修饰的是指针变量本身的内容(即为指向的变量),保证了指针变量的内容不能修改。但是指针指向的内容可以改变。
    int a = 10;
    int b = 10;
    const int* p = &a;
    
    *p = 0;//可以
    p = &b;//错误,无法修改

四、指针的运算

  1. 指针+-整数:可用于数组遍历
  2. 指针-指针:得到的是两个指针间的元素个数
  3. 指针的关系运算:大小比较

五、指针与数组

5.1数组名的理解

  • 数组名就是数组⾸元素(第⼀个元素)的地址。
  • 但是有两个例外:
    1. sizeof(数组名):sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
    2. &数组名:这⾥的数组名表⽰整个数组,取出的是整个数组的地址,地址的值依然为首元素的地址,但是地址类型为数组指针(见后文讲解)。
int main()
{
	int arr[5] = { 1,2,3,4,5};
	printf("&arr[0] = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0] + 1);
	printf("arr = %p\n", arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr = %p\n", &arr);
	printf("&arr+1 = %p\n", &arr + 1);
	return 0;
}

分析:arr和arr+1 相差4个字节;&arr 和 &arr+1相差40个字节。

5.2⼀维数组传参的本质

  • 在数组传参的时候,传递的是数组名,所以说本质上数组传参传递的是数组⾸元素的地址
  • 正因如此:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

5.3二维数组传参的本质

  • ⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址
  • 类比一维数组:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。

5.4指针数组

指针数组为存放指针的数组

创建举例:int * arr[5]

5.5数组指针

数组指针是指针

创建举例:int (*p)[10]

赋值举例:int * arr[5] = arr   (arr为数组名)

六、指针与函数

6.1函数指针变量

int (*pf) (int x, int y)
 |     |   ------------ 
 |     |        |
 |     |        pf指向函数的参数类型和个数
 |     |
 |     函数指针变量名
 |
 pf指向函数的返回类型

int (*) (int x, int y) //pf函数指针变量的类型

6.2函数指针的使用

  1. 函数指针名(参数,参数......)
  2. (*函数指针名)(参数,参数......)

注意:使用第二种方式是前面一定要加括号

#include <stdio.h>
int Add(int x, int y)
{
     return x+y;
}

int main()
{
     int(*pf)(int, int) = Add;
 
     printf("%d\n", (*pf)(2, 3));
     printf("%d\n", pf(3, 5));
     return 0;
}

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值