宿州做企业网站,重庆网站运营,网易企业邮箱登录入口登录入口,上海有名的设计公司有哪些前言#xff1a; 我们在前面的几讲中已经讲了指针的很多内容了#xff0c;现在我们开始层层递进#xff0c;要探寻更多的指针喽#xff0c;不多废话了#xff0c;直接进入正题#xff0c;开始今天的指针之旅喽#xff01; 目录#xff1a;
1.字符指针变量
1.1常量字符…前言 我们在前面的几讲中已经讲了指针的很多内容了现在我们开始层层递进要探寻更多的指针喽不多废话了直接进入正题开始今天的指针之旅喽 目录
1.字符指针变量
1.1常量字符串
1.2一个有趣的题目
2.数组指针变量
2.1数组指针变量是什么
2.2我们如何对数组指针变量初始化
3.二维数组传参的本质
4.函数指针变量
4.1函数指针变量是什么
4.2函数指针变量的创建和初始化
4.3函数指针变量的使用 正文
1.字符指针变量 在开启文章之前我先对字符串的打印提一嘴对于字符串的打印我们知道用到的占位符是%s此时仅仅提供字符串首字符地址就可以了可一定不要解引用字符指针这样仅仅会打印第一个元素的地址并且VS2022还会给你报警告一定要记住这个小编在刚开始起草这篇文章的时候就忘记这部分知识点了导致我自己重新复习了一遍知识所以我们在学习的时候一定要温习以前的知识温故而知新可以为师矣 我们知道字符型的常量用char表示那么根据指针的知识我们知道便可以知道字符指针变量是char * 来表示我们知道字符串的创建可以通过一个数组进行创建就类似
#includestdio.h
int main()
{char arr[20] {0};arr[20] {hello world};return 0;
} 在这里数组里面放置了字符串 这个我相信读者朋友们都是明白的下面我给出一串代码大家来思考一个问题我放到题目里面了
#includestdio.h
int main()
{char* p hello world; //猜一猜这里是把一个字符串放进指针变量里吗printf(%s, p);
} 先自己思考一下三二一——————其实这里是把字符串第一个元素的地址放入了指针变量p里面之后打印环节是通过第一个元素的地址开始往后打印直到遇到\0停下下面来看看这个字符串真正的样子 通过这个图可以清晰的知道p指向的地方在哪里我们把后面的字符串叫做常量字符串下面我们来进入常量字符串的环节
4.1常量字符串 我们把类似上面的代码的后面的字符串叫做常量字符串这是我们写字符串的另一种形式第一种是通过数组的方式来存放字符串现在这种为通过数组指针来传递字符串大家一定要记住这两种书写方式接下来我们来讲一下常量字符串的一个特性将之前请欣赏下面一组代码
int main()
{char* p abcdef;*p a;printf(%c, *p); //这个代码可以正常实现吗return 0;
} 大家觉得这个代码可以实现吗下面我们来运行一下 我们发现运行起来居然没有结果那么这是为什么呢对于我们代码中出现的未知错误我们可以通过调试来检测一下代码的重要性(这里展示出了调试的重要性我们在平常代码出错的时候记得自己调试而不是一味的去查询网络询问别人) 我们发现我们无法修改字符串常量的值由此我们可以知道字符串常量的一个性质字符串常量是无法被改变它是固定的它是忠诚的所以我们再平常使用字符串常量的时候一定要记得这个性质既然我们已经了解了字符串常量了下面来看一个有趣的题目可以让我们更好的理解这部分的知识 1.2.一个有趣的题目 下面请看下面的代码
#includestdio.h
int main
{ char arr1[] nihao shijie;char arr2[] nihao shijie;const char* arr3 nihao shijie;const char* arr4 nihao shijie;if(arr1 arr2)printf(arr1 and arr2 is same!\n);elseprintf(arr1 and arr2 is diffcule\n); //猜一猜最终会打印出什么if(arr3 arr4)printf(arr3 and arr4 is same!\n);else printf(arr3 and arr4 is diffcult!\n);return 0;
} 大家先思考一下这个问题一定要思考三二一 ———— 这个题的答案是下图所展示的 可能现在很多读者朋友会有疑惑为什么arr1 和 arr2是不同的呢arr3 和 arr4为什么是相同的呢下面我来解释一下大家的疑惑首先我们可以清晰的看出来arr1 和 arr2是一个字符数组虽然它们指向的都是同一个字符串但是每一次数组的建立都是开辟一块新的空间所以二者的地址都不一样所以这个是不相同的 但是对于后面两个字符串在C语言中会把常量字符串固定在一个内存中所以它们指向的内容是同一个内存所以他们是相同的这个题目一定要记住牢牢掌握我当时学习这个题目的时候就出错了所以我特地把它写到文章读者朋友们一定要牢记 小结 大家一定要好好掌握常量字符串至少做到看见它知道它是什么东西而不是啥也不会下面来进入下一篇章
2.数组指针变量
2.1.数组指针变量是什么 在讲这个之前大家一定要把数组指针和指针数组区分开虽然同样是四个字但是位置一交换那整体的意思就不一样了后者是一个数组那前边的是什么呢我们可以类比记忆存放整形地址的叫整形指针存放浮点型的是浮点型指针那么结果显然意见了数组指针就是存放数组地址的指针它的本质是指针指针数组本事是数组这两个双胞胎一定要区分开 那么我们如何写数组指针呢下面给出两个代码大家来看看二者各自是什么呢
int* p1[10];
int(*p2)[10]; 我们之前就讲述了指针数组的创建所以我们很显然的认识出了p1是指针数组那么通过排除我们可以知道第二个指的是数组指针那么为什么是这样创建呢下面我们通过图文的方式来帮助大家进行理解 上面的图片有一句话出错课[10]是指针所指向的数组元素有10个
通过图文的形式我们可以很清晰的知道为什么数组指针是这样的创建的我们进行完创建后就要初始化了下面我们来进行初始化的环节 2.2.我们如何对数组指针变量初始化 其实初始化是蛮简单的我们以及了解到了数组指针是什么了初始化就是把它翻译成代码就好了下面来展示一下数组指针如何初始化
#includestdio.h
int main()
{int arr[5] { 0 };int(*p)[5] arr;
} 其实这个初始化和整型的初始化本质都是一样的都是取地址罢了不过一个是取数的地址一个是取数组的地址而已下面小编来提问一个问题数组指针的类型是什么呢这个时候我们可以通过类比进行记忆int *p的类型是int *char *p的类型是char那么数组指针的类型自然是int(*)[10],我们将名字去掉以后就是它的类型我们可以通过调试窗口来验证我们的说法 很显然我们的说法是正确的我们现在已经了解到了数组指针的创建和初始化了那么在进入下一篇文章之前不知道大家是否还记得我以前写的文章中arr代表的是整个数组当时我并没有很详细的解释现在我们学了数组指针这个问题就好解决了因为arr的类型是int(*)[10],所以它代表的是整个元素的地址所以我们让它加一的时候它会跳过一个数组的字节所以说知识都是环环相扣的前面许多不懂得知识我们学到后面就迎刃而解了
小结 大家一定要把数组指针和指针数组区分好以后我们会经常使用它们的
3.二维数组传参的本质差点忘记写这部分呢 小编在之前的一篇文章中我记着应该是讲指针3的时候就讲过一维数组传参的本质光说一维数组的话二维数组我们就白学了它也是需要被宠幸bushi的在说这个之前我们也是需要说二维数组数组名代表的是什么
3.1二维数组数组名 我们知道一维数组的数组名是数组首元素的地址那么二维数组的数组名也是数组首元素的地址吗大家先来自己思考一下我给出一段代码以及运行图来解释一下二维数组的数组名到底是不是二维数组第一个元素的地址
int main()
{int arr[3][4] { 0 };printf(%p\n, arr);printf(%p\n, arr[0][0]);printf(%p\n, arr 1);printf(%p\n, arr[0][0] 1);printf(%p\n, arr[0][1]);printf(%p\n, arr[1][0]); //猜猜我为啥会写这个return 0;
} 我们会发现如果我们仅仅光展示前两行代码的时候大家肯定认为此时二维数组的数组名就是二维数组首元素的地址但是我们发现当指针加一的时候二者突然又不一样了这里很多读者朋友就会疑惑了这俩为啥不相同这里为了让大家更好的理解小编贴心的又打出了两个代码这个时候我们就发现arr[0][0] 1的地址和arr[0][1]的地址是一样的arr 1和arr[1][0]的地址是一样的这似乎向我们反映了一个事情arr似乎指的是第一行的地址也就是首行的地址那么事实是否就是这样呢其实这个就是正确的二维数组中数组名就是数组受行的地址为了帮助读者朋友们更好的理解小编用图文进行解释 对于具体的解释我已经放到图文里面读者朋友们先记住二维数组的数组名就是数组首行元素的地址现在我们已经明白了这个小的知识点下面我们来进行中重要部分呢二维数组进行传参的本质 3.2.二维数组传参的本质 我们知道哦在一维数组传参的时候传过去的是数组名是首元素的地址我们在传参二维数组的时候同样也是传的数组名但是数组首行的地址那么我们形参可以怎么写呢这里就用到了我们刚学的一部分内容数组指针我们可以把传过去的首行元素看做成一个一维数组的地址此时我们可以通过数组指针来接受它具体的代码如下图
void suibian(int(*p)[2], int sz) //是不是感觉到知识是换换相扣的呢
{///......
}
int main()
{int arr[3][2] { 0 };int sz sizeof(arr) / sizeof(arr[0]);suibian(arr, sz);return 0;
} 是不是感觉知识是环环相扣的呢》我么在数组指针讲完后趁热打铁讲到了二维数组传参的本质这有助于我们更好的理解数组指针当然对于二维数组的传参我们也可以写成这样类型的
void suibian(int arr[3][2], int sz) //是不是感觉到知识是换换相扣的呢
{///......
} 其实这两种写法都是可以的你想用什么就用什么
4.函数指针变量
4.1.函数指针变量是什么 这里我们同样也可以类比记忆上面我们刚讲数组指针是存放数组地址的指针整形指针是存放整形的指针所以函数指针就是存放函数地址的指针这里向我们透露出了一个信息函数也是有地址的下面我们通过一串代码来看看函数的地址是什么
#includestdio.h
void add()
{//内容我就不写了
}
int main()
{printf(%p,add);return 0;
} 可以看到函数确实会存在地址这里我们也是get到了一个新的知识点下面小编出个题考考大家前面我们学习了数组名代表着数组首元素的地址那么函数名是否也是一个地址呢下面我们来进行代码展示
void add() {}
int main()
{printf(%p\n, add); //这里会不会也和数组名和取地址数组名一样两者指的类型不同呢?printf(%p\n, add);
} 上图可以看出函数名同样也是指的函数的地址正如我在代码中提出的问题一样函数名和函数名指向的是一样吗这里小编也不多废话了其实函数名和函数名是一模一样的只不过根据个人的写法不同罢了这里一定要记住待会要用到 4.2.函数指针变量的创建和初始化
4.2.1函数指针的创建
那么既然我们知道函数指针是什么了下面我们要对它进行创建了
int (*p)(int ,int) 可能很多读者朋友对整个还是很疑惑的看不懂这是什么东西下面我们通过画图来进行进一步的解释 通过上图我们可以知道函数指针到底是如何进行创建的这个和数组指针的创建是有一点相似的所以也可以类比记忆同样的我们也要了解函数指针的类型到底是什么其实它和数组指针整形指针的类型记忆方法一样我们把指针的名字去掉就是代表的是什么类型了所以函数指针的类型是int(*)()下面我们通过调试来证明我说的 上面的代码证实了我说的正确性所以我们也要记住函数指针的类型这里也算是个小小的重点我们现在已经讲了函数指针是如何进行创建的下面我们来进行函数指针的初始化
4.2.1函数指针的初始化 其实这部分的知识很简单既然函数指针指的是存放函数地址的指针那么我们在对其使用的时候直接对函数进行取地址操作就好了下面是代码的展示 int(*p)(int, int) add; //这里的add是指的是一个add函数记住 上面便是对函数指针进行初始化这部分知识算是简单的 读者朋友们一定要掌握好我们既然讲了函数指针那么我们就要对函数指针进行使用下面进入最后一个小节对函数指针进行使用
4.3.函数指针变量的使用 我们在使用指针变量的时候往往伴随着解引用操作符*的使用所以我们在使用函数指针变量的时候也需要用到解引用操作符上面的图解解释了int * 是返回类型所以我们是不需要写它的我们仅仅使用剩下的就好了下面是对函数指针使用时的代码
int add(int x,int y) {return x y;
}
int main()
{int(*p)(int, int) add;int c (*p)(3, 4); printf(%d, c);
} 可以看出此时函数被正确的运用了所以我们在使用函数指针的时候记住忽略前面的int *就好了之后正常写就好不知道你是还记得我们在前面说过函数名就是函数地址这时候就要形成闭环了我将前面的目的就是为了这里请读者朋友们想想看我们是否可以通过指针名直接访问函数呢下面来看看代码展现
int add(int x,int y) {return x y;
}
int main()
{int(*p)(int, int) add;int c p(3, 4); printf(%d, c);
} 我们很快便可以发现原来指针名就可以直接访问函数回想一下我们在之前使用函数的时候是不是直接通过函数名就调用函数了其实我们是通过地址来访问函数的知识又再次形成了闭环可能有些读者朋友们会想为什么在使用函数指针的时候要需要括号呢其实是很简单解释的如果没有括号p首先会和后面的括号结合我们在之前就说了这就是调用函数解引用操作符操作的是地址而不是常量所以这么写是明显错误的锕大家一定要记住正确的格式 总结 今天我们讲了许多重要的内容大家一定要好好的理解并运用现在指针的知识我们已经讲了一大半了我感觉我指针已经忘记很多了今天的博客还是我通过复习得来的这更加的说明了我们一定要温故而知新知识就是要这样的我们需要重复的去记忆才能有助于我们学习我也不多废话了如果文章有误请您在评论区指出我会认真倾听你们的意见我们下一篇博客见喽