前言: 书接上回,由于文章过长,所以分了几篇文 若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持 谢谢大家 ! ! !
将常量字符串的地址串给指针时, 指针实际接收的是字符串的首字符地址
如下代码演示:
#include <stdio.h>
int main()
{
char* p = "abcdefg";
//将字符串首字符地址给p
printf("%c\n\n", *p);
//p是首字符地址,故会打印" a "
printf("%s\n\n", p);
//使用%s打印字符串时,
// 只需提供首字符的地址就行
//无需 *p
return 0;
}运行结果:

另外: 当多个指针指向同一个常量字符串时它们的地址值相同
代码演示:
#include <stdio.h>
int main()
{
char* p1 = "abcdefg";
char* p2 = "abcdefg";
//p1,p2指向同一个常量字符串
if (p1 == p2)
{
printf("p1==p2\n\n");
}
else
printf("p1!=p2\n\n");
return 0;
}运行结果:

结果显示: 当多个指针指向同一个常量字符串时,它们的地址值相同, 同一个常量字符串他们在内存中占用一块空间
数组名是首元素地址
arr == &arr[0] ;但是也有例外: 1.sizeof( arr ) ;这里计算的是整个数组 2.&arr; 这里 arr 表示整个数组,取出的是整个数组的地址
用以下各个值 +1 为例: 代码演示:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n\n", arr + 1);
printf("%p\n", &arr[0]);
printf("%p\n\n", &arr[0] + 1);
printf("%p\n", &arr);
printf("%p\n\n", &arr + 1);
return 0;
}运行结果:

(地址为十六进制) 通过运行结果,可以看到arr 和 &arr[ 0 ] 结果一致 可以见得数组名是首元素地址,二者可等价(除去例外) 但是,&arr是整个数组地址,+1 跳过整个数组 故地址 + 40(10 个 int 类型)
指针访问数组
int arr[10] = { 1,2,3,4,5,6 };int * p = arr ;printf( " %d " , *( p + 2) ) ;*( arr + i ) <=> arr [ i ] ;
创建一个数组指针变量:
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int (*p)[10] = &arr;在上面代码中,p 是数组指针变量,存放的是数组的地址 p 和 &arr 的类型是 int ( * ) [ 10 ] ;
首先, arr 是数组名,是首元素地址 一维数组传参的本质是传递数组首元素的地址,而非整个数组 即使形参写成数组形式,本质上仍然是一个指针变量
以以下代码为例: 形参声明为int arr[10]时,编译器实际处理为int arr
#include <stdio.h>
void test(int arr[10])
{
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n\n", sz);
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
test(arr);
return 0;
}运行结果:

为什么结果 sz 为 1 呢? 难道在该函数中 arr = arr [ 0 ] ? 确实如此,看似形参是 int arr [ 10 ] ,但是本质上是一个指向 arr 首元素地址的指针,也就是 arr [ 0 ] 。
所以, 一维数组传参的本质是传递数组首元素的地址,而非整个数组 即使形参写成数组形式,本质上仍然是一个指针变量
且注意: 不能像上述代码中在函数内部使用形参计算数组元素个数
类比一维数组,一维数组传参时数组名是首元素地址,形参可写成数组或指针形式 二维数组名也是首元素地址,但二维数组相当于一维数组。 故二维数组的数组的数组名就是第一行一维数组的地址 因此二维数组传参时,形参可以写成数组形式或指向一维数组的指针。
代码演示(内有注释):
#include <stdio.h>
void test(int (*arr)[5], int r, int c)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
printf("%d ", *(*(arr + i) + j));
//此处等价于 arr[i][j]
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
test(arr, 3, 5);
//传参本质是第一行地址
//故用int (*arr)[5]接收
//[5]表示五行一维数组
return 0;
}运行结果:

二维数组名也是首元素地址,二维数组相当于一维数组
所以对于 int arr [ 3 ] [ 5 ] 来说: 第一行{1,2,3,4,5}是第一个元素 第二行{2,3,4,5,6}是第二个元素 第三行{3,4,5,6,7}是第三个元素
int arr [ 0 ] [ ] 就是第一行 int arr [ 1 ] [ ] 就是第二行
且注意: arr + i 得到第i行的地址 *( arr + i ) 解引用得到第i行数组名 *( arr + i ) + j 得到第i行第j列元素的地址 最后再解引用 * ( * ( arr + i ) + j ) 得到访问具体元素 通过双重解引用 * ( * ( arr + i ) + j ) 访问具体元素,等价于 arr [ i ] [ j ] 的写法。
函数指针变量用于存放函数地址,通过地址能够调用函数。 与整型指针、数组指针类比,函数指针也是一种特殊的指针类型。
那么该如何使用函数指针变量呢?
代码演示:
#include <stdio.h>
int Add(int a, int b)
{
return a + b;
}
int main()
{
int (*pf)(int, int) = &Add;
printf("%d\n\n", pf(4, 5));
return 0;
}运行结果:

现在,我们要写一个函数,直接使主函数变量的值改变 那么该怎么写呢?
我们可以想到将主函数变量传参到函数中直接改变,如下代码:
#include <stdio.h>
void F(int g)
{
g = 100;
}
int main()
{
int g = 10;
F(g);
printf("%d\n\n", g);
return 0;
}这样我们好像成功将 g 的值改为了100,可事实真的如此吗? 运行结果:

结果仍然是 10 这是为什么呢?
因为,上述方法是传值调用,当实参传给形参时,修改形参不会影响实参,形参只是实参的临时拷贝
而要使主函数变量的值直接改变就要用到传址调用 将主函数变量的地址传给函数,形参指向实参的内存,再在函数中通过地址对变量进行直接修改 代码演示:
#include <stdio.h>
void F(int* p)
{
*p = 100;
}
int main()
{
int g = 10;
int* p = &g;//拿到g的地址
F(p);//将g的地址传给函数
printf("%d\n\n", g);
return 0;
}运行结果:

可以见得,在传址调用下,g 的值直接被改变了
故传址调用可以让函数和主函数建立真正的联系,若要在函数中修改主函数的值,只能用传址调用
用于存放指针的数组,每个元素都是指针类型
例如:
int * arr[3] = { &a,&b,&c };知道了指针数组,现在我们就可以用指针数组来模拟二维数组。 代码演示:
#include <stdio.h>
int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 6,7,8,9,10 };
int arr3[5] = { 11,12,13,14,15 };
int* arr[3] = { arr1,arr2,arr3 };
//创造一个二维数组
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);//打印二维数组
}
printf("\n");
}
return 0;
}运行结果:

有了数组指针,可以放置地址的数组,那么是不是可以将函数的地址放入数组中呢? 这就是函数指针数组
现在有 +(加) -(减) * (乘) / (除)四个函数 我们可以创建一个数组将其容纳,这就是函数指针数组
float (*Calc[5])(float, float) = { 0,Add,Sub,Mul,Div };float ( * Calc [ 5 ] ) ( float , float ) 就是函数指针数组 前面的 flaot 表示函数的返回值类型是 float 类型 后面的两个float 表示函数的两个参数是 float 类型
里面存放了加减乘除四种函数,可以进行四种计算,所以我们可以用该函数指针数组来做一个简易的计算器 代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
float Add(float x, float y)//加法
{
return x + y;
}
float Sub(float x, float y)//减法
{
return x - y;
}
float Mul(float x, float y)//乘法
{
return x * y;
}
float Div(float x, float y)//除法
{
return x / y;
}
void menu()
{
printf("******************************\n");
printf("****** 简 易 计 算 器 ******\n");
printf("****** 1.Add 2.Sub ******\n");
printf("****** 3.Mul 4.Div ******\n");
printf("****** 0.exit ******\n");
printf("******************************\n");
printf("请输入:");
}
int main()
{
int input;
float x, y;
float (*Calc[5])(float, float) = { 0,Add,Sub,Mul,Div };//给数组前巧妙加一个0可以更方便地调用函数
do
{
menu();
scanf("%d", &input);
if (input == 1 || input == 2 || input == 3 || input == 4)
{
printf("请输入要计算的值:");
scanf("%f %f", &x, &y);
printf("结果是:%.2f\n\n", Calc[input](x, y));
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输入错误,请重新输入 \n");
}
} while (input);
return 0;
}运行结果:

最后注意:
函数指针数组中的所有函数的参数和类型必须要一致
本期资料来自于:
OK,本期的指针详解到这里就结束了 由于文章过长,所以分了几篇文 若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持 本文有若有不足之处,希望各位兄弟们能给出宝贵的意见。谢谢大家!!! 新人,本期制作不易希望各位兄弟们能动动小手,三连走一走!!! 支持一下(三连必回QwQ)