【C】指针详解

 对于刚入门编程的人来说,最难理解的有两个,一个是结构体,另一个便是指针。这一节我们就来仔细讲解一下指针。

一.什么是指针?

我们学习过很多变量类型,比如int,char等类型。而指本质上也是一个变量类型,它用于存储另一个变量的内存地址。

在内存中,每一个字节都有属于自己的地址,如果我们想获取这个字节的地址,我们就可以用指针进行储存。指针也是一个变量,创建指针也要占用内存,在32位机器下,指针大小为4个字节,而在64位机器下,指针大小为8个字节。

二.指针的初始化

int *p = &a;

例如这个语句,p这个变量类型就是指针,代表着它存储着a变量的地址,并且变量是int类型的。而&a代表着对a取地址。

三.解引用

解引用代表着对指针变量进行解析,所得到的变量是指针指向的变量的数值。

printf("%d\n", *p);

这个语句就是打印p锁指向的内容的值,*p就代表对p指针解引用。我们可以这样理解,p是int*类型的,那么*p就是int类型的。

四.指针的运算

指针可以进行加法和减法运算,以指向数组中的不同元素或不同的位置。

 int arr[5] = {1,2,3,4,5};  
int *p = arr;

此时,p指向的就是数组arr的首地址(第一个元素)。而此时我们可以对p进行++操作,使得p指向下一个元素。但是要注意指针越界的问题。

当然,我们也可以对两个指针进行运算操作。

int arr[5] = {1,2,3,4,5};  
int *p = arr;
int *q=arr+4;
int num =q-p;

其中num代表的就是两个指针直接相差了多少个元素。

五.二级指针

我们说过,指针的本质是一个变量类型,那么存放指针的是什么呢?没错就是二级指针。

int a = 10;
int* p1 = &a;
int** p2 = &p1;

其中,p1就是一级指针,p2就是二级指针。以此类推,我们可以有三级、四级、...、n级,本质上其实都是变量类型。

六.空指针,野指针问题

首先我们要明白空指针和野指针分别是什么。并且我们来聊聊他们的用途。

空指针:

  • 定义:空指针是指不指向任何有效对象的指针。它通常被初始化为NULL(在C/C++中可以使用nullptr来表示)。
  • 用途:空指针常用于指示指针当前不指向任何内存地址,或者用于判断指针是否有效。通过检查指针是否为NULL,可以避免对无效内存的访问。

野指针:

  • 定义:野指针是指指向已经被释放或不再有效的内存地址的指针。换句话说,野指针的指向对象已经不存在,使用这样的指针将导致未定义行为。
  • 原因:常见的原因包括:
  • 对动态分配的内存使用freedelete后未将指针置为NULL;
  • 返回局部变量的地址;
  • 从某个作用域中退出后,指向该作用域内的对象。
int *ptr = (int*)malloc(sizeof(int)); // 动态分配内存 
*ptr =10; // 使用指针 
free(ptr); //释放内存 // ptr现在是一个野指针,因为指向已释放的内存

此时ptr就是野指针。

区别总结- 空指针是安全的,但野指针是不安全的。

  • 空指针表示不指向任何对象,而野指针则指向已失效的内存地址。

处理指针时,应谨慎使用,并确保在释放内存后将指针置为NULL,以防止出现野指针问题。

七.指针数组与数组指针

1.指针数组

我们学习过字符数组,整型数组,指针数组其实就是数组内容为指针的数组。

数组arr3就是一个指针数组。

2.数组指针

我们知道,整型指针是指向整型的指针,字符指针是指向字符的指针,那么数组指针应该就是指向数组的指针了。

int (*p)[10] = &arr;  

这里的p就是一个数组指针了。

八.函数指针以及回调函数

1.函数指针

函数指针是指向函数的指针,能够存储函数的地址,从而使得程序能够通过指针调用函数。函数指针在C和C++中广泛使用,特别是在需要回调、实现多态或动态函数调用的场景。

函数指针的定义通常包含函数的返回类型、参数类型以及指针符号。例如,如果有一个返回int,并接受两个int参数的函数 ,那么它的函数指针的类型可以定义为:

int myFunction(int, int)

函数指针可以通过函数名来进行赋值。函数名代表了函数的地址。如下:

int add(int a, int b) {  
 return a + b;  
}  

int subtract(int a, int b) {  
 return a - b;  
}  

void compute(int (*operation)(int, int), int x, int y) {  
 printf("Result: %d\n", operation(x, y));  
}  

int main() {  
 int (*funcPtr)(int, int);  

 funcPtr = add;  
 compute(funcPtr,5,3); // 输出:Result:8 
 funcPtr = subtract;  
 compute(funcPtr,5,3); // 输出:Result:2 return0;  
}  

2.回调函数

回调函数是指通过函数指针向其他函数传递的函数。被传递的函数称为回调函数,它可以在某个特定事件发生时由另一个函数调用。


typedef int (*Callback)(int, int);  

int add(int a, int b) {  
 return a + b;  
}  

int multiply(int a, int b) {  
 return a * b;  
}  

void performOperation(Callback callback, int x, int y) {  
 int result = callback(x, y);  
 printf("Result: %d\n", result);  
}  

int main() {  
performOperation(add,5,3); // 输出:Result:8  
performOperation(multiply,5,3); // 输出:Result:15 return0;  
}

我们先定义了一个回调函数类型,我们在performOperation里设置一个回调函数,我们在main函数可以任意传递类型匹配的函数,在performOperation里实现,则上述代码中的callback函数就是回调函数。

回调函数是一种灵活的编程模式,使得代码的可重用性和扩展性显著增强。无论是在异步操作、事件处理还是自定义算法中,回调函数都扮演着重要的角色。通过合理地使用回调函数,可以使得程序设计更具可读性和灵活性。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值