【C语言】带你彻底理解指针(详解)

简介: 指针的介绍:指针是一个用来存放地址的变量,可以通过指针存放的地址找到对应位置的值,对其进行使用。指针在32位平台下的大小是4个字节,在64位平台下是8个字节。(这是因为32位平台下内存地址是由32根地址线组成,一根地址线就是1bit,用4个字节就可以存下,而64位平台有64根地址线,需要八个字节才可以存下)。如果对指针进行加减与解引用操作,则±的步长与解引用操作的长度由指针类型决定,指针类型是几个字节±步长与解引用就是几个字节。

指针的介绍:

指针是一个用来存放地址的变量,可以通过指针存放的地址找到对应位置的值,对其进行使用。

指针在32位平台下的大小是4个字节,在64位平台下是8个字节。(这是因为32位平台下内存地址是由32根地址线组成,一根地址线就是1bit,用4个字节就可以存下,而64位平台有64根地址线,需要八个字节才可以存下)。

  1. 如果对指针进行加减与解引用操作,则±的步长与解引用操作的长度由指针类型决定,指针类型是几个字节±步长与解引用就是几个字节。

一、简单指针🌈

char* pc(字符指针)

int *pi(整形指针)

float* pf(浮点型指针)

还有short…double等等,拿部分举例。

1.1 指针的定义与使用

  • 这三种指针的用法基本相同,只不过char*指针存放的是char变量地址,int型指针存放的是int变量地址,float指针存放的是float变量地址。


#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
    char a = 'a';   //定义一个char类型变量
    char* pa = &a;     //*号先与pa结合说明pa是一个指针类型,指向的是char型数据的地址,将a的地址给到pa
    *pa = 'b';      //通过pa改变a的值
    printf("%c", a);  // b
    int num = 10;   
    int* pnum = &num;
    *pnum = 20;
    printf("%d", num);
    float f = 9.0;
    float* pf = &f;
    *pf = 5.0;
    printf("%d", f);
}

我们可以使用指针对指针指向的变量进行使用(修改或输出)。


1.2 指针与数组

  • 数组名就是数组的首地址。

代码示例


3307af313fe44087a82b33de549e48e3.png

  • 得到数组首地址可以通过指针遍历数组

代码示例


bb84ab14de204741a38b7385d2afcc2e.png

二、指针数组

指针数组就是用来装指针的数组

int p1[];   //(方便理解拿整形数组对比)p1与[]结合说明p1是数组,装的是int类型的数据
int* p2[];  //[]优先级比*高 p2先与[]结合,说明p2是一个数组 里面装的是int*类型的数据

举个例子

#include <stdio.h>
int main()
{
    int a = 0;
    int b = 0;
    int c = 0;
  int* arr[3] = {&a,&b,&c};   //指针数组就是数组的每个位置都存储一个地址(指针)
}

三、数组指针🌞

3.1 数组指针的定义

数组指针与指针数组名字非常相似但是却截然不同,数组指针是一个指针,指针数组是一个数组

//对比一下指针数组和数组指针
int* pa[];    //这是指针数组,优先级问题,pa先与[]结合,说明pa是一个数组,装的是int*的数据
int (*pa)[]   //这是数组指针,()优先级更高,pa先与*结合,说明pa是一个指针,指向一个int类型的数组

3.2 ”数组名“与”&数组名“

前面说了数组名代表数组首元素地址,那&数组名呢?

代码示例


304cd45628634b39b37672eafa23ca09.png

  • 对数组名与&数组名进行输出,发现地址一样


5dc3758e0aab4877ad45e2d5a613b391.png

  • 对数组名与&数组名+1,发现数组名加了四个字节,而&数组名加了十六进制的28,也就是十进制的40,为整个数组的大小。

结论:数组名与&数组名地址一样,但是数组名代表的是首元素地址,而&数组名代表的是整个数组。

3.3 数组指针使用

void print(int (*pa)[3])
{
    for(int i=0;i<2;i++)
    {
    for(int j=0;j<3;j++)
        {
      printf("%d",arr[i][j]);
        }
    }
}
int main()
{
  int arr[2][3] = {0,1,2,3,4,5};
    print(arr);   //二维数组首地址相当于 &(第一个一维数组)
}

四、函数指针🤓

函数指针就是指向函数的指针

  • 函数指针的定义
  • *函数返回值 (pa)(函数参数)

可以看作pa先与*结合,说明pa是个指针,指向一个函数

4.1函数指针的使用

代码示例

int add(int a,int b)
{
  return a+b;
}
int main()
{
  int (*pa)(int ,int) = add;
    int a = 3;
    int b = 4;
    printf("%d",pa(3,4));   //7
}

五、函数指针数组🚀

函数指针数组就是用来装函数指针的数组,需要注意每个函数指针数组的返回值和参数必须相同类型

  • 函数指针数组的定义
  • *函数返回值 (pa[])(函数参数)

可以看作pa先与[]结合说明pa是一个数组,每个位置装的是函数指针(地址)

5.1 函数指针数组的使用

#include <stdio.h>
int add(int a, int b) //需要注意函数指针数组的每个参数类型与返回值类型必须相同
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int div(int a, int b)
{
  return a / b;
}
void menu()
{
  printf("***************\n");
  printf(" 1:add 2:sub \n");
  printf(" 3:mul 4:div \n");
  printf("    0:quit   \n");
  printf("**************\n");
}
int main()
{
  int x = 0;
  int y = 0;
  int input = 0;
  int ret = 0;
  int(*p[5])(int x, int y) = { NULL, add, sub, mul, div };
  do
  {
    menu();
    printf("请选择:");
    scanf("%d", &input);
    if (input >= 1 && input <= 4)
    {
      printf("输入两个数字:");
      scanf("%d %d", &x, &y);
      ret = (*p[input])(x, y);
    }
    else if (input == 0)
    {
      break;
    }
    else
    {
      printf("请输入0-4的数字\n");
      continue;
    }
    printf("%d\n", ret);
  } while (input);
}

bfbae4e1c1f94bb5bc7a630f8ed760b3.png

六、指向函数指针数组的指针🚀🚀

函数指针数组的定义为 int (*pa[5])(参数),指向函数指针数组的指针就是:

int (( * pa)[5]) (参数) //用括号把pa括起来使得pa先与 * 结合,说明pa是一个指针,返回值类型就为函数指针数组


61fbcd3a31a44aee892e1cc1db53d6c7.png

指向函数指针数组的指针的定义

void test(char* str)
{
  printf("指针真简单,%s",str);
}
int main()
{
    //定义一个函数指针数组  
    void (*pa[5])(char*) ;
    pa[0] = test;
    //指向函数指针数组的指针
    void (*(*ppa)[5])(char*) = &pa;
    return 0;
}

七、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应 。

  • stdlib头文件下的qsort()函数就是一个回调函数,链接: qsort函数详解


完结

创作不易,还请各位小伙伴多多点赞👍关注✨收藏⭐



d89241b7267e47efa46e331647af0e19.gif
















相关文章
|
1月前
|
存储 编译器 C语言
[C语言] 初识指针
[C语言] 初识指针
|
9天前
|
存储 C语言
C语言 — 指针进阶篇(下)
C语言 — 指针进阶篇(下)
18 0
|
9天前
|
存储 C语言 C++
C语言 — 指针进阶篇(上)
C语言 — 指针进阶篇(上)
9 0
|
15天前
|
存储 程序员 C语言
C语言指针的概念、语法和实现
在C语言中,指针是其最重要的概念之一。 本文将介绍C语言指针的概念、语法和实现,以及如何使用它们来编写高效的代码。
13 0
|
16天前
|
存储 C语言
【C语言】深入解开指针(三)2
【C语言】深入解开指针(三)
|
16天前
|
存储 程序员 C语言
【C语言】深入解开指针(二)2
【C语言】深入解开指针(二)
【C语言】深入解开指针(二)2
|
16天前
|
存储 C语言
【C语言】深入解开指针(一)1
【C语言】深入解开指针(一)
|
17天前
|
C语言 索引
基于C语言的函数指针应用-消息命令处理框架
基于C语言的函数指针应用-消息命令处理框架
11 0
|
24天前
|
存储 人工智能 编译器
C语言指针详解
指针运算,指针和数组,二级指针
C语言指针详解
|
24天前
|
存储 C语言
C语言第二十四弹---指针(八)
C语言第二十四弹---指针(八)