再识C语言 DAY15 【指针(中)理论结合实践】

本文详细介绍了指针的基本概念、指针与数组的关系、指针运算规则,以及指针在传递参数和返回值中的优势,包括常量指针作为数据安全的保障。通过实例演示了如何使用指针进行大容量数据传递和多返回值函数设计。


前言

本文章总结于此视频


一、补充

指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针。指向了这个数据单元,若指针存放的值是0,则这个指针为空指针

如图所示:
在这里插入图片描述

另外,在一个系统上指针所占用的字节是确定不变的
在这里插入图片描述

我们这里使用的64位系统都是占八个字节,这是一个很关键的信息

二、数组与指针

数组与指针可以说是非常相似,数组是一些相同数据类型的变量组成的集合,其数组名及为指向该数据类型的指针。当你在写一个数组arr[]不写[ ],此时的arr就等效于指针,

如图所示

在这里插入图片描述

我们尝试一下

在这里插入图片描述

指针运算

当然,这里也涉及到了运算
在这里插入图片描述

注意:如果只是一个单独的变量就不要使用加或减,因为此时会指向非法的区域

我们可以取变量的地址来直观的学习
在这里插入图片描述

我们可以直观地观察到他们的不同,int数据类型的地址增加了四个字节char数据类型的地址增加了一个字节

所以为什么要移动一个数据类型的长度,我们前面知道指针记录的是首地址,实际上他们的类型是int 和char,我们可以想想对于int类型的数组,比如说他第一个数据地址是1,2,3,4,如果他只移动一个地址,那么你认为第二个数的地址是2,3,4,5,但实际上第二个数的地址是5,6,7,8

在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f4c04b3e7311476db2956159641522b0.jpeg#pic_center)

在这里插入图片描述

图片出处

如上图所示表示数组中5个元素在内存中的存储,其中p1指向第一个元素的地址p2表示第五个元素的地址,代码中用p2-p1,就表示的是两个指针之间的元素个数,很清楚的看到是4个元素,所以打印出来结果为4

注意事项

• 在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误
•同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告

什么是同级指针
在这里插入图片描述
比如说变量在和指针之间赋值时,当变量加上取地址&,就是正确的,或者指针加上*

如果不是同级指针,赋值时将会报错。

在这里插入图片描述

int a=1;
int* p;
*p=a;//或者
P=&a;

指针的应用

引入

有时候需要在一个函数中更改其他函数的变量,假设要交换两个函数的值。简单的思路是:

x = y;
y = x;

这完全不起作用,因为执行的二行时 x 的原始值已经被 y 的原始值替代了。因此要多写一行代码。

tem = x;
x = y;
y = tem;

这样就可以实现交换值的功能,可以编写一个函数去试试

#include <stdio.h>
void interchange(int u, int v);
int main()
{
	int x = 5, y = 10;
	printf("Origiinally x = %d and y = %d\n", x, y);
	interchange( x, y);
	printf("Now x = %d and y = %d\n", x, y);
	return 0;
}

void interchange(int u, int v)
{
	int  tem;
	tem = u;
	u = v;
	v = tem;
}

输出如下:
在这里插入图片描述

两个变量的值并未交换,我们在intercharge()中添加一些打印语句来检查错误

#include <stdio.h>
void interchange(int u, int v);
int main()
{
	int x = 5, y = 10;
	printf("Origiinally x = %d and y = %d\n", x, y);
	interchange( x, y);
	printf("Now x = %d and y = %d\n", x, y);
	return 0;
}

void interchange(int u, int v)
{
    printf("Origiinally u = %d and v = %d\n", u, v);
	int  tem;
	tem = u;
	u = v;
	v = tem;
    printf("Now u = %d and v = %d\n", u, v);
}

输出如下:

在这里插入图片描述

看来,interchange()没有问题,它交换了u和v的值。问题出在把结果传回main()时。 interchange()使用的变量并不是main()中的变量。因此,交换u和v的值对x和y的值没有影响!是否能用 return 语句把值传回main()?当然可以,在interchange()的末尾加上下面一行语句:
return (u);
然后修改main()中的调用: x = interchange(x,y);
这只能改变x的值,而y的值依旧没变。用return 语句只能把被调函数中的一个值传回主调函数,但是现在要传回两个值。这没问题!不过,要使用指针

传递参数(指针的间接访问)

传递参数时,我们分为值传递和指针传递

当我们传递的参数容量很大时,我们尽量使用指针传递

因为使用指针传递大容量的参数时,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行效率,减少了内存占用

我们举一个例子,让他更直观一些:我们假设主函数是一个学霸,我们创建新函数是一个学渣,把主函数内的一个变量假设为作业的话,如果学渣想要抄学霸作业,得到这个变量,但是主函数学霸是不会将变量直接给学渣函数的,他会先把作业抄一遍,把这个复制的作业给学渣,这样就算学渣在这个复制体作业上更改数值,也不会影响到主函数学霸的变量

作业如果是选择题还好说,但如果是作文的话,复制一份既费时又费力,这里我们就可以引用指针传递

比如说我们现在想传递一个数组,数组就属于大容量变量

#include<stdio.h>
int FindMax(int* arr,int Count)
{
    int i;
    int j=arr[0];
    for(i=1;i<Count;i++)
    {
       if(j<arr[i]);
      {
          j=arr[i];
      }                      
    }
    return j;
}
int main()
{
    int max;
    int arr[5]={10,20,30,40,50};
max = FindMax(arr,5);
printf ("%d",max);
    return 0;
}

输出

在这里插入图片描述

但是此时我们发现,我们是可以通过改变变量的值来影响主函数中变量的值
在这里插入图片描述
这时我们就想到之前学的常量指针,当我们在其他函数中改变变量的值时,编译器就会报错警告我们, 所以使用常量指针是我们指针传递中的一个保护措施
在这里插入图片描述
相比较,值传递隔离,数据安全,但是当遇到大容量的数据是会占用较多的空间和时间。指针传递可以处理大容量的数据。为了使数据更安全,我们可以使用常量指针。

指针输出参数

使用指针传递输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计
我们发现第一个应用是避免主函数与子函数使用同一套数据,而第二个应用是反过来的,我们要利用主函数和子函数使用同一套数据,实现多返回值

因为C语言有一个弊端,那就是只能有一个返回值,当我们要返回多个值时,就需要用到指针的这个特征

例题:找到数组中最大的数,和其出现的次数。

#include<stdio.h>
int FindMax(int* max,int* count,int* arr,int lenght)
{
    int i;
    *max=arr[0];
    *count=1;
    for(i=1;i<lenght;i++)
    {
       if(*max<arr[i])
      {
         *max =arr[i];
         *count=1;
      }       
      else if(*max==arr[i])
      {
          (*count)++;
      }               
    }
}
int main()
{
    int MAX,Max;
    int Count;
    int arr[5]={10,50,30,40,50};
MAX = FindMax(&Max,&Count,arr,5);
printf ("%d\n",Max);
printf ("%d",Count);
    return 0;
}

运行:

在这里插入图片描述
所以说指针打破了C语言的只能有一个返回值,理论上我们可以用指针写出无数个返回值


如果您发现文章有错误请与我留言,感谢

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马职音人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值