热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言常量与变量的深入理解及其影响

本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。

C语言 常量与变量

常量与变量

正所谓静中有动,动中有静,常量与变量亦是如此,它们之前相互依赖,相互影响。关于常量与变量,很多朋友可能觉得没有什么好介绍的,它实在是太简单了,单从字面上看就知道什么意思?我想说的不是关于常量与变量的概念,而是其深入的实质。

其实很多朋友在学到后面指针的时候经常会出现,段错误,晕指针(我对那些指针恐惧者的症状叫法),野指针等问题,都是因为对常量和变量的理解不够深入,基础理解不够踏实。

 

常量:其值不会发生改变的量,称为常量。它们可以和数据类型接合起来分类。比如:整形常量,浮点型常量,字符常量等等,常量是可以不经过定义和初始化,而直接引用的。

常量分类:常量又分为:直接常量和符号常量。

直接常量又叫做:字面常量。如12,0,4.6,’a’,”abcd”

符号常量:如宏定义的:#define PI 3.14

特点:常量的值在其作用域内不会发生改变,也不能再被赋值。其在出现时就被当作一个立即数来使用。也就是说,只能被访问,被读,而不能被写,被赋值。

其实,你一旦声明了一个常量,那么常量所在的内存空间就被加上了只读的属性,它有点类似于const关键字。

 

变量:其值在其作用域内可以改变的量称为变量。一个变量应该有一个名字,在内存中占据一定的存储空间。变量在使用前必须要定义。每个变量都有自己的地址。

变量分类:变量依据其定义的类型,分为不同类型,如:整型变量,字符型变量,浮点型变量,指针型变量等等。

特点:变量其值可以发生改变,意味着它可以被覆盖,被写入,被赋值。每个变量必须要有一个名字和它所在内存空间绑定,如图xxx所示。

《C语言 常量与变量》

图xxx 变量内存空间示意图

代码中声明整型变量a,它的类型已经决定,那么它的大小也就是4个字节(32位机上),那么在内存中就有连续的四个字节与之对应,a变量名就代表了这四个字节的空间,a变量的地址就是连续四个字节的开始的地址0x000。就好像是饭店里每个房间都有一个地址,如201室代表二楼每一个房间,叫201不太雅观,我们起个名字叫:牡丹厅。那么,我们人为的将“牡丹厅”这个名字和201房间绑定在了一起。当我们说到牡丹厅,就知道是201房间,同样当我们说201房间我们也知道是牡丹厅。

同样的道理,当我们说a变量,就知道是从0x000这个地址开始的4个字节,当我们说0x000地址就知道这是a变量的空间。那么既然a是变量也就是说它所代表的空间里的数据是可以修改的,同样0x000地址处的数据也是可以修改的。

变量名和变量的值:

变量名是在变量的声明的时候,该名字就和内存中一块地址绑定在一起了。可以通过变量名直接找到对应的内存区域,也可以通过地址找到其内存区域。

变量的值是变量所对应的内存区域内存放的二进制序列。变量的值不会因为变量的类型发生了改变而改变,当变量被转换为对应类型时,内存区域的二进制序列以该类型的形式翻译出来。这也是强制类型转换能够成立的原因。

例如:

[cpp]
view plain
copy

  1. int a = 97;  
  2. char ch1 = ‘a’;  
  3. char ch2 = (char)a;  
  4. char *p = (char*)a;  

第一行代码:整型变量a在内存中是以97的二进制形式存放的,当使用它时,会被以十进制形式表现出来。

第二行代码:字符变量ch1的ASCII 码是97,也是以97的二进制存放的,使用时,会被以字符’a’的形式表现出来。

第三行代码:将整型变量a强制类型转换成字符型,a变量里的值没有变,变的是它的类型,它里面的值还是97的二进制,它类型变成了char,97的二进制变成char型,表现出来就是字符’a’。

第四行代码:声明一个字符型指针变量p,p是个变量,它里面的值可变,它的值是整型变量a的值强制类型转换成了字符指针类型。这个时候p里的值还是97的二进制,只不过这个97的意义已经代表了一个字符型指针,也就是一个指向字符的地址了。

由此可见:变量在内存中存放和它的值没有关系,而是和它的类型相关的。同样我们也可以得出:一个二进制序列对于计算机本身而言没有任何意义,计算机根本不知道这个二进制数据是干什么的,只有具体到它的类型时或出现在合适的场合时,才能代表具体的意义。如果一串二进制数据出现在地址总线上,它代表是一个地址,如果该相同数据出现在数据总线上,它代表是一个数据。所以,当我们看到一个数据时,比如:3.1415926,不能把它戴上定向思维的帽子认为它就是PI,而是要看清它的本质,它就是一堆二进制代码。

我们来看下下面的例子:

1.

char ch = ‘a’;

int a = (int)ch;

printf(“%d %c\n”, a, ch);

ch是什么?ch里装的是什么?a是什么?a里面装的是什么?打印什么?

2.

int add = 0x12345678;

int *p = (int*)add;

add是什么?add里装的是什么?p是什么?p里装的是什么?*p又是什么?&p又是什么?

3.

#define PI 3.14

int a = PI;

printf(“%d\n”, a);

上面的代码有没有问题?

4.

#define PI 3.14

printf(“%d\n”, PI);

代码有没有问题?

5.

#define PI 3.14

int a = PI;

PI = 3.1415926;

int b = PI;

printf(“%d %d\n”, a, b);

代码有没有问题?

6.

char *str = “hello world”;

printf(“%s\n”, str);

str = “goodbye world”;

printf(“%s\n”, str);

代码有没有问题?

 

答案:

1.       测试对变量类型的理解和类型转换。ch是字符型变量,ch里是字符’a’的二进制数,a是整型变量,a里面是字符’a’的二进制数的整型表示方式,以十进制数表示出来97。打印结果为97 和 a。

2.       测试对整型和地址类型转换。add是一个整数变量,add里是0x12345678的二进制数,以十进制表现出来,p是一个整型指针变量名,p里面是0x12345678的二进制数,以地址的方式表现出来,代表地址0x12345678。*p是通过*去访问地址0x12345678这个地址处的数据(如果你试图去打印它,会出错,因为这个地址你不一定有权限去访问)。&p是取出整型指针变量p的地址,因为p是一个变量,它也有自己的地址,所以可以取出它的地址来(见上面变量的定义)。

3.       宏定义一个常量PI,PI这个符号代表了3.14,在代码执行前的预处理阶段第二行int a = PI,已经被替换为了int a = 3.14,将3.14赋值给整型,会舍弃掉小数点后面部分结果,仅保留整数部分,打印结果为3。

4.       和上面3一样,在预处理阶段被替换成了printf(“%d\n”, 3.14),结果为1374389535,这是因为将浮点型的3.14在内存中的数据,以整型来表现的。

5.       第三行PI = 3.1415926会出错,PI是个常量其被替换成了3.14 = 3.1415926,3.14是个字面常量,不能被赋值。错误信息为“向无效左值赋值出错”(关于常见错误信息,见C语言常见错误详解章节)。

6.       第三行*str = “goodbye world”出错,第一行中将字符串常量“hello world”的首地址给了字符指针变量str,第三行试图将“goodbye world”的首地址,通过*str的访问方式覆盖str指向的字符串常量“hello world”。这句话理解起来都比较费劲,因为这里有两个错误:

  •  试图向常量里写数据。

              “hello world” 是字符串常量,那么这个字符串空间里的内容不能改变。

  • 指针变量里应该放地址,字符串都是以首地址为地址。

              向一个地址里写入字符串应该使用strcpy。*str只是代表了str指向的字符串中的第一个字符,将字符串地址写入到一个字符里肯定不行。

 

关于上面说的,可能现在还不太好理解,请读者通读完C语言指针和数组之后再来细品,定会有不同程度的深入理解。

 

++++++++++++++++++++++++++++++++++++++++++

《C语言深入理解系列 – 常量与变量》

查看其它博文请关注原创作者。

本文系本站原创,欢迎转载! 转载请注明出处:

http://blog.csdn.net/mr_raptor/article/details/7212155

++++++++++++++++++++++++++++++++++++++++++


推荐阅读
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
author-avatar
用户r5oydafsky
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有