写点什么

【C 语言】进阶指针 night

作者:謓泽
  • 2022 年 7 月 15 日
  • 本文字数:3092 字

    阅读完需:约 10 分钟

【C语言】进阶指针night

🚩write in front🚩

🔎​​Hello,大家好我是謓泽,一起共同学习,多多指教(●'◡'●)🔎

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝

✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩

💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🖊

📢2021 年度博客之星物联网与嵌入式开发 TOP5~2021 博客之星 Top100~阿里云专家 ^ 星级博主~掘金⇿InfoQ 创作者~周榜 92»总榜 1382👋

💥指针的安全

指针的安全问题很重要也就是在程序中如何使用,如果你能避免指针的危险性那么你指针就肯定学的还是不错的。指针固然是很好用的,但好用的同时又避免不了指针自身实际上是很危险的一个东西,所以我们在使用指针的操作一定要考虑指针的安全性避免程序挂掉或者造成崩溃。


我认为对指针的安全常见问题存在这③个问题

①:野指针

②:空指针

③:字节(地址)的改变

以上这三种都是我认为我们会常见的一些问题所在,在博客当中我也都写到过。所以当我们在使用指针的时候应该思考下我所定义的这个指针是不是一个安全性高的指针。

再举出一些例子供大家参考。示例代码如下 👇


#include <stdio.h>
int main(void){ char str='c'; int *ptr=(int *)&str; *ptr=10086; printf("%d\n",ptr); return 0;}
复制代码


解析代码如下👇:

①:指针 ptr 是一个 int * 类型的指针,它指向的类型是 int 。它指向的地址就是 str 的首地址,在 32 位系统为 4 字节,64 位为 8 字节。

②:改变了 str 所占的一个字节,还把和 str 相临的高地址方向的三个字节也改变了。这三个字节是干什么的?只有编译程序知道,而写程序的人是不太可能知道的。也许这三个字节里存储了非常重要的数据,也许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,这三个字节的值被改变了!这会造成崩溃性的错误。 (关键点在于强制改变 char 的类型导致取出的字节数发生改变,而这个是我们并不清楚的)


那么相信你对这个能完全掌握的话,对指针的理解会更上一层楼。 那么再举出一个例子供大家去理解:示例代码如下 👇


#include <stdio.h>
int main(void){ char a; int *ptr = &a; ptr++; *ptr = 10086; printf("%d\n", *ptr); return 0;}
复制代码


解析代码如下👇

这段代码实际上是可以运行成功的,但是它的漏洞实际上很多。就比如很明显的一点:

从 char 到 int 实际上类型并不兼合。**

ptr 对指针 ptr 进行自加 1 运算后,ptr 指向了和整形变量 a 相邻的高地址方向的一块存储区。这块存储区里是什么?这可出现了巨大的 bug,如果一个项目这样的话,很有可能就会丢失一块重要的数据。

而*ptr = 10086,这里就更加离谱了,所以这个指针就近指向了哪里?



🖊指针练习

既然都看到这里了,还不上手做下关于指针的练习题吗(╹ڡ╹ )

相信当你做完的时候会对指针理解会更加的深刻哟,当然一下几道是相较于来说比较基础。

🔥练习 ①

题目→输入一个整形数组为 10 个元素,使指针累加起来数组所有元素之和。

本道题目的解题步骤实际上很容易,接下来说说解题思路↓

根据要求先输入十个元素,使用循环遍历数组当中的所有的元素,最后再把所有的元素进行相加。那么实际上本道题目就完成了。简单明了(¬‿¬)

示例代码如下所示↓


#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#define num 10int main(void){  int sum = 0;//总和  int i = 0;  int* arr[num] = { 0 };  int* p = arr;  printf("请输入十个元素->:");  for (i = 0; i < num; i++)  {    scanf("%d", &arr[i]);  }  while (*p < arr)  {    sum += *p;//每一次元素的相加    *p++;//指向下一个元素  }  //打印sum  printf("sum = %d\n", sum);  return 0;}
复制代码


运行结果🖊

请输入十个元素->:10 20 30 40 50 60 70 80 90 100

sum = 550

🔥练习 ②

题目→创建一个函数实现用指针实现两个值的交换,不能创建临时变量来进行交换替换。

本道题目有两点我们需要注意下↓

  1. 指针实现两个值的交换。

  2. 不能创建临时变脸来进行交换。

这里来说下,为什么要用指针变量进行交换。通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。如果你不通过指针的方式进行交换的话,一旦出了函数的形参当中就立马会销毁其中的值,就达不到交换的结果。


其次,不能创建临时变量来进行交换。其实这个很好办用按位异或就可以了,那么我们要知道按位异或是什么才行接下来来介绍下什么是按位异或(^∀^●)ノシ

那么我们要知道按位异或的运算规则才行。0^0=0,0^1=1,1^0=1,1^1=0;

示例代码如下所示↓


#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
void swap(int *x, int *y){ //按位异或 在这里我们可以使用代入法:假设 是 x = 1,y = 2 *x ^= *y;//x = x^y // 0001 ^ 0010 = 0011 = 3 此时x = 3 *y ^= *x;//y = x^y // 0011 ^ 0010 = 0001 = 1 此时y = 1 *x ^= *y;//x = x^y // 0011 ^ 0001 = 0010 = 2 此时x = 2 结果 x = 2,y = 1 }int main(void){ int a = 0, b = 0; printf("请输入两个数字:"); scanf("%d %d", &a, &b); printf("a,b交换前:a = %d,b = %d\n", a, b); swap(&a, &b); printf("a,b交换后:a = %d,b = %d\n", a, b);
return 0;}
复制代码


运行结果🖊

请输入两个数字:10 20

a,b 交换前:a = 10,b = 20

a,b 交换后:a = 20,b = 10

🔥练习 ③

题目→创建自定义函数,从而实现 strcat()的功能,用指针进行实现。

strcat() 的功能就是连接字符串,假设在 arr1 当中是"Hello ",而 arr2 当中是'Cyyds',此时所连接起来的字符就因该是"Hello Cyyds",如果不了解 strcat()的函数声明可以去看看,这样对做题的帮助是很大的。

示例代码如下↓


#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#include<assert.h>char *My_strcat(char *dest, const char *src){  assert(dest && src != NULL);//断言  char *ret = dest;  while (*dest != '\0')//'\0'的ASCLL码值就是0  {    dest++;  }    //dest指向的是'\0'  while (*dest++ = *src++)  {    ;  }  return ret;}int main(void){  char arr1[20] = "hello C";   char arr2[20] = "yuyan";  printf("%s\n", My_strcat(arr1, arr2));  return 0;}
复制代码


运行结果🖊

hello yuyan

🔥练习 ④

那么接下来我们再来看一组代码,示例代码如下↓

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void Revise(int *p1)
{
  *p1 = 1314;
}
int main(void)
{
  int *p1 = NULL;
  int p = 520;
  p1 = &p;

  printf("*p1 = %d\n , p1 = %d\n , &p1 = %d\n , &(*p1) = %d\n , p = %d\n , &p = %d\n", *p1, p1, &p1, &(*p1), p, &p);
  Revise(p1);
  printf("*p1 = %d\n , p1 = %d\n , &p1 = %d\n , &(*p1) = %d\n , p = %d\n , &p = %d\n", *p1, p1, &p1, &(*p1), p, &p);
  return 0;
}

试着把上面的代码给分析出来,其实不难就是这"指针比较臭"而已(ง •_•)ง

这个 &p1 的地址的本身的地址,而我们取 &(*p1)的地址是取解引用 p1 的值然后再取出 &(*p1)的地址。也就相当于是取地址 p 赋值给指针变量 p1。如果你觉得我这句话对你来说不怎么理解的话,那么多看几遍还是可以理解的。



📢最后 の talk

指针可以说在 C 语言真的算比较难了也是因为指针有些人就被劝退了,但是指针学好了。但是学好 C 语言指针好处是大大滴多的(这个在前面的初阶指针已经讲的非常清楚了)。刚开始学指针的时候我特别懵,尽管现在我也觉得蛮懵的。但是起码比刚开始好多了不至于连指针数组和数组指针都分不清不会用了(●'◡'●),指针这个东西一定要花时间多看多打代码多调试。

💬如果你是刚学 C 语言的初学者或者是指针,推荐看看前面博主写的一篇初阶指针的内容🌹

发布于: 刚刚阅读数: 3
用户头像

謓泽

关注

一起happy! 2022.01.29 加入

谁也不知道旅途的终点是怎么样的,现在只不过是开始。便全力以赴!终点必将是星辰大海。 2021年度博客之星物联网与嵌入式开发TOP5 2021博客之星Top100 阿里云专家博主^星级博主 CSDN⇿掘金⇿InfoQ[创作者]

评论

发布
暂无评论
【C语言】进阶指针night_7月月更_謓泽_InfoQ写作社区