上一节 C语言基础部分我们了解了C语言中的指针知识,这一节我们开始深入指针的学习,重点是数组指针,函数指针。
第一、自定义函数传递地址和传递值得理解
为什么在main函数中的变量 i 作为形参传递给自定义函数update后,形参i的内存地址和main函数中的变量i的内存地址不一样?
#include <stdio.h>
void TranslateValue(int i) {
//传递的是值,不是内存地址
printf("自定义函数TranslateValue形参i的内存地址:%p\n", &i);
printf("自定义函数TranslateValue形参i的内存地址:%d\n", i);
}
void TranslateAddr(int *i) {
//传递的是内存地址
printf("自定义函数TranslateAddr形参i的内存地址:%p\n", i);
}
int main(){
int i = 100;
printf("main函数中的变量i的内存地址是:%p\n", &i);
printf("main函数中的变量i的内存地址是:%d\n\n", i);
TranslateValue(i);
TranslateAddr(&i);
return 0;
}
输出结果:

自定义函数的使用.png
说明:
1、形参在函数进栈时,有自己的内存地址;
2、作为参数传递的仅仅是内存中的值;
3、如果传递的变量i的内存地址时,这是就是相同的内存地址;
第二、了解多级指针
#include <stdio.h>
int main(){
int number = 100;
int *number_p = &number;//一级指针:指向变量的内存地址
int **number_p_p = &number_p;//二级指针:指向一级指针的内存地址
int ***number_p_p_p = &number_p_p;//三级指针:指向二级指针的内存地址
printf("一级指针number_p的本身的地址是:%p 所指向的内存地址是:%p 所指向的内存值是:%d\n", &number_p, number_p, *number_p);
printf("二级指针number_p_p的本身的地址是:%p 所指向的内存地址是:%p 所指向的内存值是:%d\n", &number_p_p, number_p_p, *number_p_p);
printf("三级指针number_p_p_p的本身的地址是:%p 所指向的内存地址是:%p 所指向的内存值是:%d\n\n", &number_p_p_p, number_p_p_p, *number_p_p_p);
return 0;
}
输出结果:

多级指针.png
说明:
多级指针可以理解成成是指向指针地址的指针;
第三、数组和数组指针
#include <stdio.h>
int main(){
int array[] = {1, 2, 7, 4, 5, 6};
printf("数组的地址是:%p\n", array);
printf("数组首元素地址是:%p\n", &(array[0]));
printf("取数组的第三个元素的值是:%d\n\n", *(array + 2));
printf("此时的*array+2 为什么没有取第三个元素的值呢?:%d----%d\n\n", *array,*array+2);
for (int i = 0; i < 6; i++) {
//由此可以看到内存地址的大小是4个字节,其实就是int类型在内存中的size
printf("通过数组指针来输出数组的第 %d 的元素的内存地址是: %p 值是: %d \n", i, array + i, *(array + i));
}
return 0;
}
输出结果:

数组和数组指针.png
说明
1)数组的内存地址就是数组首元素的内存地址;
2)数组名,可以理解为指向数组首元素的指针;
3)数组取值:3.1 可以通过数组下标的方式来获取,
**3.2 可以通过:数据名(即数组的首元素地址)+ 元素的偏移量 == 取值元素的地址 ,然后通过*来获取内存中的值;**4)由于数组名就是数组的首地址,那么就可以直接将数组名赋值给一个指针,无需使用&来取地址;
5) 数组在内存中是一片连续的内存地址;
6) 数组在取值和偏移量操作的时候,取值的运算符的优先级是优于偏移量操作的+ -操作符的;*
**例如:*(array+2) 与 *array +2 是不一样的,需要使用括号来限定运算符的顺序**
第四、函数指针
#include <stdio.h>
//将函数指针传递给一个函数
int operate(int (*method)(int ,int),int number ,int number2){
printf("函数指针的内存地址:%p\n",method);
return method(number,number2);
}
//两数相减的结果
int reduce(int number, int number2) {
return number - number2;
}
int main(){
int num = 100;
int num2=45;
printf("获取reduce函数的地址是:%p\n",&reduce);
printf("reduce函数的函数名地址是:%p\n",reduce);
printf("通过函数指针来调用函数执行后的结果是:%d \n",operate(reduce,num,num2));
return 0;
}
输出结果:

函数指针.png
说明:
1)函数名其实就是函数在内存中的地址,所有可以不使用&来获取函数地址;
2)函数指针的格式 : 例如:int (method)(int ,char) ------- int 返回值类型 (method)函数指针名, (int ,char) 形参;**
3)使用场景:类似于java中的回调函数;或者kotlin中的block