数组指针、指针数组、常量指针、指针常量、函数指针、指针函数
在C语言中,常常有一些相似的名词出现,但其实代表的是不同的含义。本文仅阐述自己对这些概念的理解和分享。
1.数组指针与指针数组的异同点
2.常量指针和指针常量的异同点
3.函数指针和指针函数的异同点
接下来我将用一段程序来说明这6者之间的关系,示例程序已在visual studio中验证完成并附在文末。
//数组指针:指向数组的指针 int(*ptr)[5]
//指针数组:一个数组,元素都是指针 int *arr[5]
//常量指针:指向常量的指针,指向内容是常量,内容无法修改,地址可以修改 const int *ptr
//指针常量:指针本身是常量,指向不能改变,可以修改内容,地址无法修改 int *const ptr
//函数指针:指向函数的指针,通过调用该指针来使用该函数,返回类型(*函数名)(参数列表)
//指针函数:返回指针的函数,返回类型 *函数名 (参数列表)
数组指针:是一个指向整个数组大小的指针;对指针进行加减运算时,移动的是整个数组的大小;常用在二维数组的传递中。
语法类型:数据类型(*指针名)[]。

指针数组:是一个元素都是指针的数组;常用于存储字符串数组;每个指针可以指向不同长度的数据。
语法类型:数据类型 *指针名[]。

常量指针:指向常量的指针,指向内容是常量;内容不能修改,地址可以修改(可以通过修改地址间接修改内容);常用于函数参数,防止修改数据。
语法形式:const 数据类型 * 指针名;数据类型 const * 指针名。

指针常量:指针本身是常量,指向不能改变;可以修改内容,地址无法修改;必须要在定义时初始化 。
语法:数据类型* const 指针名。

特殊类型:常量指针常量:const 类型名 * const 指针名;地址和内容都无法改变。
函数指针:指向函数的指针,通过调用该指针来使用该函数;常用于回调函数、函数表;可以指向匹配签名的任何函数。
语法类型:返回类型 (*函数名)(参数列表)。

指针函数:返回值是指针类型的函数。
语法类型:返回类型 *函数名 (参数列表)。

记忆技巧:
1.数组指针和指针数组 :()中有*指针名;是指针,指向数组;无(),指针名和[]结合,是数组,元素是指针。
2.常量指针和指针常量:const 在*左边,指向的值不变,是常量指针;const在*右边,指向的地址不变,是指针常量。tips:指针常量需初始化。
3.函数指针和指针函数:()中有*指针名;是指针,指向函数;无(),指针名和(参数列表)结合,是函数,返回值是指针。
总结:()中的优先级最高,若()中有*指针名,则是指针,后面的属性定义指向数组or函数;无()保护*指针名,则是一种具体的类型。
应用场景:
1.数组指针:二维数组作为函数参数,矩阵处理。
2.指针数组:字符串数组,命令行参数。
3.常量指针:函数参数保护,防止意外修改,只可读,不可修改。
4.指针常量:硬件寄存器地址访问,固定地址访问,可以修改内容。
5.函数指针:回调函数,函数表。
6.指针函数:工厂模式,动态内存分配。
注意事项:
1.数组指针和指针数组声明注意()的位置。
2.常量指针只是限制通过指针修改数据,但不限制修改指针变量。
3.指针函数不要返回局部变量的地址(栈内存会在函数返回后释放)。
4.函数指针需要和所指向函数的签名完全匹配。
示例程序:
#include<stdio.h>
int add(int a, int b);
int sub(int a, int b);
int* funa(int* p);
int main()
{
//数组指针:指向数组的指针 int(*ptr)[5]
//指针数组:一个数组,元素都是指针 int *arr[5]
//常量指针:指向常量的指针,指向内容是常量,内容无法修改,地址可以修改 const int *ptr
//指针常量:指针本身是常量,指向不能改变,可以修改内容,地址无法修改 int *const ptr
//函数指针:指向函数的指针,通过调用该指针来使用该函数,返回类型(*函数名)(参数列表)
//指针函数:返回指针的函数,返回类型 *函数名 (参数列表)
//1.数组指针:指向数组的指针 int(*ptr)[5]
printf("数组指针\n");
int arr[5] = { 1,2,3,4,5 };
int i;
int(*ptr1)[5] = arr; //数组名就是数组地址 取地址方式1
for (i = 0; i < 5; i++)
{
printf("%d\n", (*ptr1)[i]);
}
int(*ptr2)[5] = &arr; //数组名就是数组地址 取地址方式2
for (i = 0; i < 5; i++)
{
printf("%d\n", (*ptr2)[i]);
}
printf("数组指针\n");
//2.指针数组:一个数组,元素都是指针 int *brr[5]
printf("指针数组\n");
int a = 1, b = 2, c = 3;
int *brr[3] = {&a,&b,&c};
for (i = 0; i < 3; i++)
{
printf("%d\n", *brr[i]);
}
for (i = 0; i < 3; i++)
{
printf("%p\n", brr[i]);
}
printf("%p\n", &a);
printf("%p\n", &b);
printf("%p\n", &c);
printf("指针数组\n");
//3.常量指针:指向常量的指针,指向内容是常量,内容无法修改,地址可以修改 const int *ptr
//可以通过修改地址来修改值
int ab = 100;
int bc = 200;
const int ac = 10;
const int *ptr3 = &ab; //指向ab,但通过指针无法修改ab的值
printf("常量指针\n");
printf("%d\n", *ptr3);
printf("%p\n", ptr3);
//*ptr3 = 30;
ptr3 = ∾
printf("%p\n", &ab);
printf("%p\n", &ac);
printf("%d\n", *ptr3);
printf("%p\n", ptr3);
ptr3 = &bc;
printf("%d\n", *ptr3);
printf("%p\n", ptr3);
printf("常量指针\n");
//4.指针常量:指针本身是常量,指向不能改变,可以修改内容,地址无法修改 int *const ptr
int abc = 99, bac = 88, aaa=55, bbb=66;
printf("指针常量\n");
printf("%p\n", &bac);
printf("%p\n", &abc);
int* const ptr4 = &abc;
*ptr4 = 77;
printf("%p\n", ptr4);
printf("%d\n", *ptr4);
*ptr4 = aaa;
printf("%p\n", ptr4);
printf("%d\n", *ptr4);
*ptr4 = bbb;
printf("%p\n", ptr4);
printf("%d\n", *ptr4);
printf("指针常量\n");
//ptr4 = &bac;
//5.函数指针:指向函数的指针 返回类型(*func)(参数列表)
printf("函数指针\n");
int abcd = 0;
int(*func)(int a, int b);
func = NULL;
printf("%p\n", add);
printf("%p\n", func);
func = &add;
printf("%p\n", func);
abcd = func(3, 4);
printf("%d\n", abcd);
printf("%p\n", func);
printf("%p\n", sub);
func = sub;
printf("%p\n", sub);
printf("%p\n", func);
abcd = sub(9, 4);
printf("%d\n", abcd);
printf("函数指针\n");
//6.指针函数:返回指针的函数,返回类型 *函数名 (参数列表)
printf("指针函数\n");
int aabb = 123;
int *ptr5;
int* ptr6= funa(&aabb);
printf("%p\n", &aabb);
printf("%p\n", funa);
ptr5 = funa(&aabb);
printf("%p\n", ptr5);
printf("%p\n", ptr6);
printf("%d\n", *ptr5);
printf("%d\n", *ptr6);
printf("指针函数\n");
return 0;
}
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int* funa(int *p)
{
return p;
}

浙公网安备 33010602011771号