5.C语言指针篇

什么是指针?

  • 指针就是内存地址

指针变量

  • 简称指针,用于存储指针(即内存地址)

  • 定义格式

    • 数据类型* 变量名 = &要获取指针的变量
    • 数据类型:要跟指向变量的类型保持一致(比如,int a = 10; int * aa = &a;)
    • *:标记
  • 指针变量占用的大小,跟数据类型无关,只跟编译器有关

    • 32位(x86):4字节 64位(x64):8字节
  • 给指针变量赋值的时候,不能把一个数值赋值给指针变量

指针的作用

查询/存储数据

  • 格式
    • *指针名
    • *:解引用运算符
int a = 10;
int* p = &a;
printf("%d", *p); // 10
*p = 100;
printf("%d", *p); // 100
printf("%d", a); // 100

作用1:操作其他函数中的变量

#include<stdio.h>

void swap(int* p1, int* p2);

int main()
{
	int a = 10;
	int b = 20;
	printf("前:%d %d\n", a, b);
	swap(&a, &b);
	printf("后:%d %d\n", a, b);
	return 0;
}
// 使用指针交换两个变量里面的数据
void swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

作用2:在函数中用于返回多个值

#include<stdio.h>

void compare(int arr[], int len, int* max, int* min);

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int max = arr[0];
	int min = arr[0];
	int len = sizeof(arr) / sizeof(int);
	compare(arr, len, &max, &min);
	printf("Max: %d\n", max);
	printf("Min: %d\n", min);
	return 0;
}
// 找出数组中的最大最小值
void compare(int arr[], int len, int* max, int* min)
{
	for (int i = 0; i < len; i++)
	{
		if (arr[i] > *max)
		{
			*max = arr[i];
		}
		else if (arr[i] < *min)
		{
			*min = arr[i];
		}
	}
}

作用3:将函数的结果和状态分开

#include<stdio.h>

int getR(int a, int b, int* res);

int main()
{
	//定义一个函数,求前者对后者的余数,后者有可能是0,此时函数状态异常(0不能作为除数)
	int a = 10;
	int b = 0;
	int res;
	int flage = getR(a, b, &res);
	if (!flage)
	{
		printf("余数为:%d", res);
	}
	return 0;
}

int getR(int a, int b, int* res)
{
	if (b == 0)
	{
		return 1; // 异常
	}
	*res = a % b;
	return 0; // 正常
}

指针运算

  • 步长:指针移动一次,走了多少个字节
常见数据类型 字节数
char 1
short 2
int 4
long 4
long long 8
#include<stdio.h>

int main()
{
	int a = 10;
	int* p = &a;
	printf("%p\n", p);		// 000000FE00FBF844
	printf("%p\n", p + 1);	// 000000FE00FBF848
	printf("%p\n", p - 1);	// 000000FE00FBF840
	return 0;
}
  • 有意义的操作
    • 指针跟整数进行加、减法操作(每次移动N个步长)
    • 指针跟指针进行减法操作(间隔步长)
  • 无意义的操作
    • 指针跟整数进行乘除法操作
      • 指针指向不明
    • 指针跟指针进行加、乘、除操作
      • 指针指向不明(或表示不明意义)

指向不明的指针

  • 野指针
    • 指针指向的空间未分配
#include<stdio.h>

int main()
{
	int a = 10;
	int* p1 = &a;
	printf("%p\n", p1);		// 000000BD365CF734
	printf("%d\n", *p1);	// 10

	//野指针
	int* p2 = p1 + 10;
	printf("%p\n", p2);		// 000000BD365CF75C
	printf("%d\n", *p2);	// 189
}
  • 悬空指针
    • 指针指向的空间已分配,但是又被释放了
#include<stdio.h>

int* method();

int main()
{	
	int* p1 = method();
	printf("---------\n");
	printf("函数外:%p\n", p1);		// 函数外:0000001D361EF614
	printf("函数外:%d\n", *p1);	// 函数外:25 相同指针,却得到了不同的数据结果,说明该指针指向空间已被释放 
	return 0;
}

int* method()
{
	int a = 10;
	int* p = &a;
	printf("函数内:%p\n", p);		// 函数内:0000001D361EF614
	printf("函数内:%d\n", *p);		// 函数内:10
	return p;
}

无类型指针

  • void* p;

  • 特点:

    • 无法获得数据,无法计算,可以接收任意地址
  • 应用场景(增强函数的通用性)

//以指针作用1中交换变量数据为例
#include<stdio.h>

void swap02(void* p1, void* p2, int len);

int main()
{
	long a = 10L;
	long b = 20L;
	swap02(&a, &b, 4);
	printf("a = %ld\n", a);	// a = 20
	printf("b = %ld\n", b);	// b = 10
	return 0;
}

void swap02(void* p1, void* p2, int len)
{
	// 步骤1:将通用指针void*转为char*(关键!char*每次操作1字节)
	char* p3 = p1;
	char* p4 = p2;
	char temp = 0; // 临时变量,存单个字节的值
	// 步骤2:循环len次(len是要交换的数据的总字节数)
	for (int i = 0; i < len; i++)
	{
		// 步骤3:交换当前指向的1个字节
		temp = *p3;	// 把p3指向的1个字节的值存到temp
		*p3 = *p4;	// 把p4指向的1个字节的值覆盖到p3的位置
		*p4 = temp;	// 把temp里原来p3的值覆盖到p4的位置
		// 步骤4:指针后移1字节,指向下一个待交换的字节
		p3++;
		p4++;
	}
}

二级指针和多级指针

  • 再次申明

  • 指针数据类型:

    • 跟指向空间中的数据的数据类型,保持一致
  • int a =10;
    //一级指针
    int* p = &a;
    //二级指针
    int** pp = &p;
    //三级指针
    int*** ppp = &pp;
    //...
    
  • 作用:

    • 二级指针可以操作一级指针记录的内存地址

数组指针

  • 概念:

    • 指向数组的指针,称为数组指针
  • 作用:

    • 方便操作数组中各种数据
  • 实例:

    • #include<stdio.h>
      
      int main()
      {
      	//利用数组指针遍历数组
      	int arr[] = { 10,20,30,40,50,60,70,80,90 };
      	int len = sizeof(arr) / sizeof(int);
      	//获得数组指针的两种方式
      	int* p1 = arr;
      	int* p2 = &arr[0];
      	for (int i = 0; i < len; i++)
      	{
      		printf("%d\n", *p1++); // 每打印一次数组元素,数组指针便向后移动一步(这里的数组是int型,也就是向后移动4个字节)
      	}
          return 0;
      }
      

数组指针的细节

  • arr(数组名) 参与计算时,会退化为指向第一个元素的指针
  • 特殊情况
    • sizeof 运算时,不会退化,arr依旧是一个数组整体
    • &arr 获取地址时,不会退化,arr依旧是一个数组整体
#include<stdio.h>

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int* p1 = arr;
	int* p2 = &arr;
	printf("%p\n", p1);			// 0000005E52AFF728
	printf("%p\n", p2);			// 0000005E52AFF728
	//arr(数组名) 参与计算时,会退化为指向第一个元素的指针
	printf("%p\n", arr + 1);	// 0000005E52AFF72C = p1 + 4 步长:4个字节
	//sizeof 运算时,不会退化,arr依旧是一个数组整体
	printf("%d\n", sizeof(arr));// 20
	//&arr 获取地址时,不会退化,arr依旧是一个数组整体
	printf("%p\n", &arr + 1);	// 0000005E52AFF73C = p1 + 10 步长:20个字节(数据类型*数组长度)
}

数组指针和指针数组

  • 数组指针:指向数组的指针

    • int* p1 = arr; 步长:int(4字节)
    • int (*p)[5] = &arr; 步长:int * 5(20字节)
  • 指针数组:存放指针的数组

    • int* arr[5];
    • 容易混淆的写法
      • int*p[5];

函数指针

  • 格式:返回值类型 (*指针名)(形参列表)= 方法名;
  • 作用:利用函数指针,可以动态地调用函数
#include<stdio.h>

void method1();
int method2(int num1, int num2);

int main()
{
	//定义函数指针
	void (*p1)() = method1;
	int (*p2)(int, int) = method2;
	p1();
	printf("-------\n");
	int num = p2(10, 20);
	printf("%d\n", num);
	return 0;

}

void method1()
{
	printf("method1\n");
}

int method2(int num1, int num2)
{
	printf("method2\n");
	return num1 + num2;
}
posted @ 2026-03-14 15:45  Shadow001  阅读(1)  评论(0)    收藏  举报