指针在c语言中的运用,怎么理解C语言中的指针,如何运用?

恰好我之前写了一系列介绍 C 语言的文章,介绍了什么是指针,以及为什么要使用指针,下面摘录一部分,感兴趣的话,可以点我了解更多。

什么是 C语言指针?

不同的数据类型的主要区别在于占用的存储空间不同。我们知道,C 程序是运行在计算机的内存中的,因此 C 程序的变量也是存在于内存中的。C 标准规定 char 类型占用一个字节的存储空间,对其他整型却没有做规定,现在为了解释的方便,我们假设 int 类型的数据占用内存 4 个字节。

假设我们如下定义了两个变量:signed char i = 3;int j = 8;

那么,i 占用了 1 字节的内存空间,j 占用了 4 字节的内存空间,请看下图。

方框表示内存空间,内部表示存储的值。我们把内存逐字节编号,方框外部的数字表示方框的编号(这样的内存“编号”即所谓的“内存地址”)。修改变量 i 的值,实际上就是修改地址为 4000 的内存空间里的值。那反过来呢?如果我修改了地址为 4000 的内存空间里的值,i 的值会相应改变吗?答案是肯定的,请继续往下看。

上图中的内存地址“4000”是我为了解释方便随意取的。那么,在实际应用中,变量 i 的地址如何获取呢?C 语言提供了“&”运算符,就是获取变量地址的。请看下面的例子:#include int main()

{

signed char i = 3;

int j = 8;

long p1 = (long)&i;

printf('p1: %ld ', p1);

return 0;

}

我们取出了 i 的地址,把它强制转换为 long 型(关于强制类型转换,可参考上一节),传递给 p1 了。编译执行,发现变量 i 的地址被打印出来了。这说明,C 程序变量的地址也是一个整数。

按照上面的说法,修改 i 的值除了直接对 i 赋值以外,还可以通过修改 p1 地址处的内存空间里的数值。那,怎样才能“通过修改 p1 地址处的内存空间里的数值”修改 i 的值呢?

上面的代码实例中,我们使用了 long 型变量 p1 存储了 i 的地址。事实上,C 语言有专门的数据类型存储地址,定义方式也很简单,就是:“类型描述符 * ”,例如,可以定义以下变量存储地址:signed char *p1 = &i;int *p2 = &j;

p1 和 p2 就是 C 语言中所谓的指针类型,因为 i 是 signed char 类型的,所以定义了 signed char * 类型的指针存储 i 的地址。j 是 int 类型的,所以定义了 int * 类型的指针存储 j 的地址。另外,C 语言提供了“&”运算符取变量地址,与之对应的,还提供了“ * ”运算符从相应地址内存里取出数值。

好了,了解了 C 语言的指针类型和“ * ”运算符,现在来看看如何“通过修改 p1 地址处的内存空间里的数值”修改 i 的值。请看如下代码:signed char *p1 = &i;

*p1 = 5;

printf('i=%d ', i);

编译运行,发现程序输出“i=5”,这样我们就实现了“通过修改 p1 地址处的内存空间里的数值”修改 i 的值。在定义变量时,” * “放在变量符号前,可以定义指针变量。在定义完指针变量后,“ * ”放在变量前,就表示从地址取值的运算符了。另外,“ * ”还可以表示乘法运算符,读者自己思考什么情况下,“ * ”表示乘法运算符。

以上的操作,实际上就是 C 语言的指针操作,可以看出它一点也不神秘,接下来几节,我们将继续讨论 C 语言的指针,比如为什么 int 类型的变量 j 的地址要使用 int* p2; 定义,而不能使用 signed char* p2; 定义,使用指针为何能写出紧凑、高效的 C 程序等等。

为什么要使用指针?

在开始讨论为什么使用 C 语言指针之前,先介绍一下复杂点的指针,这是新知识,也是铺垫。不想看铺垫可以往后翻一翻。

前面几节介绍了 C 语言中指针,也讨论了数组指针和指针数组的区别,但归根结底,至今我们说的都是基础数据类型定义的指针,C 语言有复合数据类型,那么它有复合数据类型的指针吗?答案是肯定的,事实上,在 C 语言中复合类型指针的使用相当广泛。

先来看看结构体指针。还是从实例出发,我们定义一个结构体类型,它有两个成员,分别是 sleep_time(睡觉时间) 和 work_time(工作时间),然后定义这种结构体类型的变量和指针:struct week{

double sleep_time;

double work_time;

};

struct week w;

struct week *pw = &w;

可以通过结构体指针 pw 访问 week 结构体的成员:(*pw).sleep_time = 7.0;

这样写有点麻烦,因此 C 语言非常贴心的提供了“->”运算符,所以我们还可以这样通过结构体指针访问成员:pw->sleep_time = 7.0;

为什么要使用 C 语言中的指针

好了,现在我们已经知道 C 语言中的结构体指针怎么使用了,铺垫完了。但是,明明使用结构体变量 w 就能很好的读写 week 结构体啊,为什么要用结构体指针呢?这不是麻烦了吗?为什么要使用结构体指针,其实可以延伸到“为什么要使用指针”,本节将以结构体指针为例讨论一下这个问题。

是的,仅仅访问 week 的 sleep_time 成员,只使用结构体变量 w 就足够了,再通过 pw 访问真的麻烦了。但是工具会不会带来方便,要看我们怎么使用,不能因为高射炮打蚊子不方便就说高射炮没用。恰当的使用结构体指针,有利于我们写出更加紧凑,效率更高的 C 程序。

一周有五天工作日,两天周末,一般来说,在工作日(weekday),人们的睡觉时间较短,工作时间较长,所以我们定义 weekday 函数来规划工作日的时间:void weekday(struct week wd)

{

wd.sleep_time = 7.0; // 7 小时

wd.work_time = 8.5; // 8.5 小时

}

而在周末(weekend)则反过来,工作间较短,睡觉时间较长,所以我们定义 weekend 函数来规划周末的时间:void weekend(struct week we)

{

we.sleep_time = 9.0; // 9 小时

we.work_time = 2.5; // 2.5 小时

}

这两个函数很好的规划了一周的睡觉和工作时间,但是却并不好用。为什么呢?因为它俩只在自己内部规划了,我们外界看不到啊!想在 main 函数把规划好的时间打印出来都办不到,因为它俩在自己内部规划好以后,就把“规划书”销毁了。这里把 weekday 和 weekend 函数的局部变量比作“规划书”,函数退出后,局部变量就自动销毁了。可以参考《c语言入门5,一文彻底弄懂函数的形参和实参》一节。

可能你会说,那我可以把“规划书”返回给 main 函数啊,让 weekday 和 weekend 函数有返回值就可以了:struct week weekday(struct week wd)

{

wd.sleep_time = 7.0; // 7 小时

wd.work_time = 8.5; // 8.5 小时

return wd;

}

struct week weekend(struct week we)

{

we.sleep_time = 9.0; // 9 小时

we.work_time = 2.5; // 2.5 小时

return we;

}

int main()

{

struct week w;

w = weekday(w);

printf('weekday, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

weekend(w);

printf('weekend, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

return 0;

}

是的,这的确是一个解决问题的办法,main 可以把 weekday 和 weekend 函数的“规划书”打印出来了。

但是这种解决问题的办法有一点臃肿,很多程序员把这样的代码称为“不优雅”的代码。你看,main 现在有一份空的“规划书”,需要 weekday 和 weekend 函数处理。weekday 和 weekend 函数能处理,但是它们要复制一份“规划书”回到自己内部做,这种复制就造成了空间浪费。此外,weekday 和 weekend 函数做完了规划书,还要把“规划书”再从自己内部取出,return 给 main,这就有时间浪费。

更节约资源,更有效率的做法是:weekday 和 weekend 函数处理这份“规划书”时,直接处理 main 里的“规划书”就可以了。不要复制后再处理,完事了还要在从自己内部传出。那,weekday 和 weekend 函数应该怎么修改呢?请看:void weekday(struct week *wd)

{

wd->sleep_time = 7.0; // 7 小时

wd->work_time = 8.5; // 8.5 小时

}

void weekend(struct week *we)

{ we->sleep_time = 9.0; // 9 小时

we->work_time = 2.5; // 2.5 小时

}

int main()

{

struct week w;

weekday(&w);

printf('weekday, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

weekend(&w);

printf('weekend, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

return 0;

}

看到了没,利用指针,整个 C 代码简洁多了。weekday 和 weekend 函数接收到的参数都是 main 里结构体变量 w 的地址,所以它俩都是直接操作 w 的。这样就不用在自己的栈帧里复制一份 w 再处理了,也不用在处理完毕还要 return 给 main 了。

看到这里,你可能会说,什么嘛,不就是用指针代替了结构体做参数吗?指针说不定比结构体还要耗空间呢!对吗?一起来看下:结构体变量 w,它占用内存至少两个 sizeof(double) 的空间(一个 double 型数据通常占用 8 字节空间)。而一个指针,不管它是什么类型的,在大多数 32 位计算机中,它只占 4 字节空间,在大多数 64 位计算机中,它也仅仅占 8 字节空间。所以使用指针做 weekday 和 weekend 函数的参数,在空间上,绝对是比直接使用 week 结构体节约空间的,何况指针还提升了效率,简洁了代码。如果是一个 char 型变量,它只占用 1 字节空间,这时使用指针的确更浪费空间。但是如果是一个非常复杂的结构体,它占用的内存空间甚至达几千字节,这时使用指针就非常节约空间了。所以说,工具是死的,人是活的。

到这里,相信你已经了解 C 语言指针在节约空间,提升程序效率方面的作用了。事实上,这里我们介绍的仅仅是指针的冰山一角,在以后的文章里,你会愈发觉得 C 语言指针的强大的。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/541695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式(一)单例模式的七种写法

1. 饿汉模式 public class Singleton { private static Singleton instance new Singleton(); private Singleton (){}public static Singleton getInstance() { return instance; } } View Code这种方式在类加载时就完成了初始化,所以类加载较慢,…

scala 字符串转换数组_如何在Scala中将字节数组转换为字符串?

scala 字符串转换数组Byte Array in Scala is an array of elements of a byte type. String in Scala is a collection of the character data type. Scala中的字节数组是字节类型的元素的数组。 Scala中的String是字符数据类型的集合。 将字节数组转换为字符串 (Convert byt…

智能关机软件 c语言,智能关机软件

智能关机软件是一款免费共享关机软件。智能关机软件不但具有定时关机、自动关机的功能,而且还可以进行定时提醒信息、打开文件、打开网页、重启计算机、注销用户、锁定计算机、计算机休眠、计算机待机、关闭显示器,并且可以进行多任务计划,可…

wget: command not found

-bash: wget: command not found的两种解决方法 今天给服务器安装新LNMP环境时,wget 时提示 -bash:wget command not found,很明显没有安装wget软件包。一般linux最小化安装时,wget不会默认被安装。可以通过以下两种方法来安装:1、rpm 安装rp…

数据库数据规范化看不懂_数据库管理系统中的规范化

数据库数据规范化看不懂DBMS中的规范化 (Normalization in DBMS) Every table must have a single idea. The method by which we divide tables approximately is called normalization and the rest used for normalization is a functional dependency. For the normalizati…

c 语言开发一个四则运算器,C++实现四则运算器(无括号)

本文实例为大家分享了C实现无括号的四则运算器的具体代码,供大家参考,具体内容如下完成度更高的带括号版本可以看C实现四则运算器(带括号)对于无括号的计算器,实现起来比较容易,下面让我们一步步实现。举例首先明确需要实现怎样的…

iOS开发之解决系统数字键盘无文字时delete键无法监听的技巧

最近在做用户登录获取验证码时添加图形验证码功能,就是只有正确输入图形验证码才能收到后台发送的短信验证码。效果如下: 看起来虽然是个小功能,但是实际操作起来,会发现苹果给我们留下的坑,当然更多的是自己给自己挖的…

c ++查找字符串_C ++结构| 查找输出程序| 套装1

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>#include <math.h>using namespace std;struct st {int A NULL;int B abs(EOF EOF);} S;int main(){cout << S.A << " " << S.B;return 0;}Output: 输出&#xff1a…

二级c语言加油,二级C语言 备考指南及常见问题(2013版)

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼3、关于上机操作部分的复习最好买一本上机题库方面的教材&#xff0c;或打印、阅读南开百题之类的电子文档。配合上机模拟软件(无纸化考试软件)&#xff0c;上机练习是必须的。上机软件一般有100套题多一点&#xff0c;每套有程序填…

开放定址散列表

再散列之后散列函数要重新计算。 // kaifangliaobiao.cpp : 定义控制台应用程序的入口点。 //使用平方探测解决冲突问题时&#xff0c;散列表至少空一半时&#xff0c;总能插入一个新的元素#include "stdafx.h" #include<iostream> using namespace std;#ifnde…

合并两个链表数据结构c语言,合并两个链表.

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #define N1 10#define N2 10struct list{int date ;struct list *next;};main(){struct list *p1,*p2,*p3,*p4,*head,*head1,*head2,*p;int n0;head1head2NULL;p1p2(struct list *)malloc(sizeof(struct list));p1->da…

c ++查找字符串_C ++结构| 查找输出程序| 套装2

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>using namespace std;int main(){typedef struct{int A;char* STR;} S;S ob { 10, "india" };S* ptr;ptr &ob;cout << ptr->A << " " << ptr->STR[2];…

连接fiddler后手机无法显示无网络

升级了fiddler到4.6版本&#xff0c;手机设置代理后提示无网络&#xff0c;试试以下解决方法&#xff1a; 1.fiddler升级后对应的.net framework也要升级&#xff0c;安装最新的.net framework 4.6&#xff0c;升级安装后&#xff0c;可以正确抓包啦 2.如果上述方法无效&#x…

android 人脸解锁 锁屏动画,人脸保护锁(人脸识别锁屏)

这是一款十分炫酷的锁屏工具&#xff0c;还记得电影中的特工所用的人脸识别锁吗&#xff1f;这款应用也能让你过过瘾&#xff01;人脸识别锁屏安卓版是一款用人脸做密码来打开手机屏保锁的一个APP。不仅可以作屏保锁&#xff0c;也可以单独保护某些重要程序不被偷窥,例如查看短…

dbms_排名前50位的DBMS面试问答

dbms1) What are the drawbacks of the file system which is overcome on the database management system? 1)在数据库管理系统上克服的文件系统有哪些缺点&#xff1f; Ans: Data redundancy & isolation, difficulty in accessing data, data isolation, and integri…

linux时间

CST代表中国标准时间rtc实时时钟linux主要有两种时间硬件时钟 clock系统时钟 date修改时间 date 03300924必须是两位或者 date -s 2017:03:30将系统时间同步到硬件时间 hwclock -w将硬件时间同步到系统时间 hwclock -s转载于:https://blog.51cto.com/12372297/1911608

查找Python中给定字符串的所有排列

Python itertools Module Python itertools模块 "itertools" are an inbuilt module in Python which is a collection of tools for handling iterators. It is the most useful module of Python. Here, a string is provided by the user and we have to print a…

android 图片叠加xml,Android实现图片叠加效果的两种方法

本文实例讲述了Android实现图片叠加效果的两种方法。&#xff0c;具体如下&#xff1a;效果图&#xff1a;第一种&#xff1a;第二种&#xff1a;第一种是通过canvas画出来的效果:public void first(View v) {// 防止出现Immutable bitmap passed to Canvas constructor错误Bit…

Win10系列:VC++ 定时器

计时器机制俗称"心跳"&#xff0c;表示以特定的频率持续触发特定事件和执行特定程序的机制。在开发Windows应用商店应用的过程中&#xff0c;可以使用定义在Windows::UI::Xaml命名空间中的DispatcherTimer类来创建计时器。DispatcherTimer类包含了如下的成员&#xf…

dbms系统 rdbms_DBMS与传统文件系统之间的区别

dbms系统 rdbmsIntroduction 介绍 DBMS and Traditional file system have some advantages, disadvantages, applications, functions, features, components and uses. So, in this article, we will discuss these differences, advantages, disadvantages and many other …