字符指针变量
在C语言中,我们可以这样:
char ch = 'a';
char* pc = &ch;
来创建一个字符指针变量。
我们还可以这样:
const char* ptrc = "hello csdn";//代码2
来创建一个字符指针变量。
在代码2中,我们可能会认为是把字符串 hello csdn 放到了字符指针ptrc中,但其实不是,本质是将字符串首字符的地址放入字符指针ptrc中,代码2中就是将h的地址放进ptrc中。
我们再看一段代码:
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
注意:“ str1 == str2 ”并不是表示比较两个字符数组的内容是否相同,而是比较的是数组首元素地址是否相同;
“ str3 == str4 ”表示比较这俩字符串首字符的地址是否一样。
运行结果:
我们通过第一个if语句的结果发现:str1和str2的内容虽然一样,但是他俩的首元素地址不同;
通过第二个if语句的结果发现:被const修饰的字符指针str3和str4这俩不仅内容一样,连字符串的地址也是一样的。(用const修饰是为了保证str3和str4指向的内容不被修改)
这里str3和str4指向的同一个字符串,也就是说指向了同一个地址(即首字符的地址)c/c++通常会将常量字符串存放在单独的区域,当几个指针指向一个内容相同的字符串时,他们实际指向的是同一个地址;但是当我们用相同的字符串去初始化不同的数组时就会开辟出不同的内存块(个人理解是将存放在单独区域内的常量字符串复制两份,然后再赋值给数组str1和str2)
数组指针变量
我们知道:
整型指针变量:是存放整型变量的地址,能够指向整型数据的指针
字符指针变量:是存放字符变量的地址,能够指向字符数据的指针
那么我们可以类比以上得出数组指针变量:存放的是数组的地址,能够指向数组的指针变量
我们来看一段代码:
int* p[10];//代码1
int (*p)[10];//代码2
哪一个代表的是数组指针变量呢?答案是代码2
原因:操作符“ [ ] ”的优先级高于“ * ”,所以对于代码1,p会先和“ [ ] ”结合,p就成了数组名,那么此时代码1表示的就是一个能够存放10个元素的数组,每个元素的数据类型是“ int* ”;
来看代码2,操作符“()”可以改变优先级,让p先和“ * ”结合,这样p就是一个指针变量,再和后面的“ [ ] ”联系起来,此时代码2表示的就是一个数组指针变量,这个指针指向一个能够存放10个元素数组,每个元素的数据类型是“ int ”。
怎么初始化数组指针变量
既然是数组指针变量,那就得拿数组的地址来初始化
直接看代码:
int arr[10] = { 0 };
int(*parr)[10] = &arr;
//注意&arr和arr的区别!!
//&arr取出的是整个数组的地址
//arr表示的是数组首元素的地址(不明白可以看之前写的文章)
在调试界面我们也能看到&arr和parr的类型都是int[10]*
函数指针变量
依旧可以使用类比的方法来学习函数指针变量:函数指针变量存放的是函数的地址,能够通过这个地址来调用函数。
它的形式和数组指针类似:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pAdd)(int, int) = &Add;
//int(*)(int,int)是pAdd的类型(去掉名字就是类型)
//也可以写成int(*pAdd)(int,int) = Add
//函数名就是函数的地址
return 0;
}
我们只需要将“ [ ] ”改成“(形参1,形参2,...,......)”即可。
再看一段代码:
通过这段代码我们发现:函数名就是函数的地址,之所以写成“ &Add ”的形式是为了方便理解
我们可以通过函数指针来调用指针所指向的函数:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pAdd)(int, int) = &Add;//Add
printf("Add(3,5)的结果是:%d\n", Add(3, 5));
printf("(&Add)(3,5)的结果是:%d\n", (&Add)(3, 5));
printf("pAdd(3,5)的结果是:%d\n", pAdd(3, 5));
printf("(*pAdd)(3,5)的结果是:%d\n", (*pAdd)(3, 5));
return 0;
}
运行结果:
通过上面这段代码,我们可以认为“ pAdd、*pAdd、Add、&Add ”是等价的
函数指针数组
通过名字我们可以知道函数指针数组是一种数组,它是用于存放函数指针(地址)的数组。
int (*parr[10])(int ,int);//函数指针数组的例子
//parr的数据类型为int(*)(int,int)[10]
函数指针数组和函数指针非常像,函数指针数组就是在函数指针的变量名旁边加上“ [ ] ”,由于“ [] ”的优先级高于“ * ”,因此parr会先和“[]”结合表示这是一个数组,而剩下的部分“ int(*)(int, int) ”表示的是函数指针的类型。
这个例子包含的信息:int (*parr[10])(int ,int)表示parr是一个函数指针数组,这个数组有10个元素,每个元素的类型是函数指针类型,也就是 int(*)(int, int),这个数组的类型为int(*)(int,int)[10]。
(所有文章仅仅是对个人所学知识的梳理,如有不对的地方还请指出)