C++ 变量也许和其他语言的变量没有什么差别.就是用来存储一些可能会变值的容器.
当然 C++ 变量里又分为 原子类型 的(int , char ,bool 等等),复合类型 的(struct ,class ,union).
这篇内容会比较侧重与于记录些原子类型的变量的使用和注意事项.其实我想很多都记录在原文中,但是无奈怕篇幅太长.而且让人生厌.所以给出了一些链接让有兴趣的同学方便查看.

-- 变量类型 --

我们可以按照变量的实际保存数据的类型分割为一下几个类别

  • 整型
    int (4字节)
    short (2字节)
    long (在 32 位系统下是 4 字节,64 位系统则是 8 字节)
  • 实型
    float (4字节)
    double (8字节)
  • 字符型
    char (1字节)
    wchar_t (这个在内存中的所占的大小,可能根据使用的 字符集 不同而不同,比如你在 VS 上用默认是 utf16le 那么它大致是占 2 个字节,gcc 上默认是 utf8 ,其宽度是 4 字节)
    [还有在使用 wchar_t , char 类型时候需要注意区分要使用与之对应的容器或函数.比如 char 对应的字符串容器是 string,而 wchar_t 对应的容器是 wstring,而在屏幕输出上 char 对应的 cout,而 wchar_t 对于的是用 wcout]
  • 布尔类型
    bool (1字节)
  • 指针类型
    函数指针 (例如 int (*pFunc) (void),这里定义了一个 pFunc 函数指针,指向返回值为 int ,参数列表为 void 的函数指针.这个是属于 c 范畴的内容啦.所以这里不详细介绍了有兴趣的可以点这个 链接(函数指针) 或这个 链接( C++ 成员函数指针) 参考看看.我在一开始时候学习到这个特性的时候,还是很痛苦的.经常和返回值为指针的函数原型弄混)
    指针变量(用于记录某些变量地址)

-- 变量定义 --

这里简单的列举出来变量的定义形式(引用必须在声明时候显示赋值):

int i; // 定义整型变量
int *p; // p 为指向整型数据的指针变量
int a[n]; // 定义整型数组 a 有 n 个元素
int *p[n]; // 定义指针数组 p,有 n 个指向整型指针
int f(); // f 为返回整型函数值的函数
int *p(); // p 为返回一个指针的函数,该指针指向整型数据
int (*p)(); // p 为指向函数指针,该函数返回一个整型值
int **p; // p 为一个指针变量,它指向一个整型的指针变量
int &p = a; // p 为整形变量 a 的引用
int *& p2 = p; // p2 为整形变量指针 p 的引用(可以查看这里的例子)

那在实际的开发中在定义变量时候最好给变量显示赋予一个初始值.为什么这么做呢,若你在定义变量的时候并未显示赋值,那么你的变量一开始里面保存的数据是不确定的.比如定义一个整形 int a; 这句话仅仅只是为 a 这个变量分配了一个内存空间,而 a 的内容取决于你当前分配那块内存的值,那这个就是很不确定的了.所以假设你不小心使用了一个为经初始话的变量,可能就会导致程序崩溃等等.

-- 整形变量 --

整形变量就是用来存放整数的地方.那么整数又是如何被存储在内存当中的呢?答案是以 补码 (这里是有关 [原码] ,[反码] ,[补码] 的相关说明,若想知道的更深入可以 [点这里])的形式存放在内存中.若了解了这个的话,那么算术异常你也就大致知道是什么原因了,为何两个很大的数相加会得到一个负数.
还需要注意的是 C++ 对于 1000 0000 表示的数变不在是 0 而是 -128(即 -127-1).因为在有符号数中表示 -0 的这个数实际意义上是最小负数在减一. 当然实际是应为 -128 刚刚好对应的二进制补码为 1000 0000 除符号位外也.
在计算机当中其实它只识别二进制的形式,即 0101 这种的形式(因为没有什么电路的专业知识所以这里也不多做解释,以免误导到你.我的理解是电路中存在两种状态即,有电,没电.对应的即是 1, 0).
因为计算机的整形存储是以二进制的形式.所以有个细节可以注意,对于整数进行 2 的次幂乘除的时候,可以用移位来实现.这样效率会更高

下面来扩展下思路.既然计算机存储的数据格式是二进制,那么我们就简单下如何用布尔运算来实现有符号整数加法与乘法的方式.这里只是做个扩展思路,实际计算机的操作可能有被优化过.

-- 加法 --

一个加法可以拆分成布尔运算的 *与* 与 *异或* 的组合的多次迭代
两个数相与后再左移 1 位可以得到这两个数相加的 *进位*,
而两个数的异或可以得到两个书相加的 *本位*
若 *进位* 为 0 那么,当前的 *本位* 及是加法的运算结果,若不为 0 重复将 *进位* 与 *本位* 继续进行 *与* 与 *异或* 直至 *进位* 为 0.
举个例子吧
第一轮:
本位: 101001 ^ 001001 = 100000
进位: 101001 & 001001 = 001001 << 1 = 010010
第二轮:
本位: 100000 ^ 010010 = 110010
进位: 100000 & 010010 = 000000(为 0 结束)
所以的到 101001 与 001001 的相加结果 110010

-- 乘法 --

乘法的本质就是加法的迭代,那么我们可以用更贴近计算机处理的思路来想问题.若 n * m,可以讲 m * n 拆分成 m*(2^x + 2^y + 2^w + ...)
举个例子: 比如 6 * 5 , 然后我按照 m*(2^x + 2^y + 2^w + ...) 的拆分可以得到 6(2^2 + 2^0),那下面我就用二进制的表达式列出下运算公式.
110 * 101 = (110 << 000) + (110 << 010) = 110 + 11000 = 11110
这里看似正常,但是若 n,m 中出现了负数的话运算结果却会令人瞪目结舌.正像上面说的负数也是以补码形式存放在内存中的.那么我们可能要在运算前对 m,n 进行一步处理,即把 m,n 还原成源码再然后在进行运算.当然在运算时候切记不要把符号位带入运算当中.而且获得运算结果后记得把结果转换为补码的形式.

-- 浮点型变量 --

既然了解了整形变量是如何存储在内存当中的,那么我们也了解下浮点型是如何存储在内存中的吧.浮点型是遵照 [IEEE 754] 标准.也可以点 [这里] 简单地了解下什么是浮点数.也正因为它存储数据的方式.导致它所表达的具体值可能存在精度不够准确.

-- 字符型变量 --

既然计算机只能识别些 1010 的二进制那么字符又是如何被存储的呢?当然你不可能 'a' 这个字符直接写入内存中,那么就找个折中办法吧.我们用一个数值来对应一个字符.然后把这个记录在内存中,接着我们就可以通过这个数值找个这个字符.下面我们就简单的了解一些相关的专业名词和对于的解释吧.

  • 字符(Character)是指人类语言中最小的表义符号.例如 'A'、'B' 等;想知道更多点 [这里]
  • 字符编码(Encoding) 是指给定一系列字符,对应每个字符赋予一个特殊的数值,并可以用这数值来代表对应的字符.例如,我们给字符 'A' 赋予数值 0,给字符 'B' 赋予数值 1,则 0 就是字符 'A' 的编码;想知道更多点 [这里] 一帮我们使用比较多的编码集是 ASCII , Unicode(utf-8,utf-16), GBK.
  • 字符集(Character Set) 是指给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就.例如,给定字符列表为{'A','B'}时,{'A' => 0, 'B' => 1}就是一个字符集;
  • 字符序(Collation) 是指在同一字符集内字符之间的比较规则;确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);

这里可能要补充一点 当你在使用 char 时候,若第一个字符大于 0x80,那么就必须检查下一个字节,才能判断一个完整的字符.

-- 变量作用域 --

在使用变量的时候应该注意变量的生存周期(即变量的作用域),以免引用了已经脱离作用域的变量,比如返回了一个指向函数局部变量的指针.可参看下表:

变量存储类别       函数内                 函数外
作用域 存在性 作用域 存在性
auto 与 register √ √ × ×
static(局部) √ √ × √
static(外部) √ √ √(只限本文件) √
extern √ √ √ √

在初步了解变量的作用域,顺带这里也可以初略解下 C++ 在编译的程序时候会把程序内存分为的几个部分:

  • 栈区: 由编译器自动分配释放的,存放着函数的参数值,局部变量的值,其操作方式类似于数据结构中的栈(申请)速度快,但程序员无法控制.
  • 堆区: 由程序员分配释放,程序员不释放程序结束时可能回收,分配方式类似链表(申请速度慢,易产生内存碎片).
  • 全局区/静态区: 全局变量与静态变量的存储是放一块的,初始化全局变量在一块区域内,未初始化的静态变量在相邻的另一块区域内,程序结束后由系统释放,内存在整个运行期间都存在.
  • 字符常量区: 常量字符串就是放在这里,程序结束后由系统释放.
  • 程序代码区: 存放函数体的二进制代码,在这里存放的变量又称字面常量

C++ 记事本: 变量的更多相关文章

  1. 6 小时 Python 入门

    6 小时 Python 入门 以下操作均在 Windows 环境下进行操作,先说明一下哈 一.安装 Python 1.官网下载 Python 进入官网(https://www.python.org), ...

  2. java中eclipse的安装和JDK的环境变量的配置以及记事本的使用

    2020-04-09 23:26:15 学习java的第一步当然就是环境配置了,java中的配置作为小白刚刚开始肯定会有点一点晕头转向的,开没等开始入门呢!就要准备放弃了.哈哈哈哈,没关系的,都是这么 ...

  3. JAVA/GUI程序之记事本

    自上半年JAVA课程结束后,再也没有看过JAVA了,最近不是很忙,又简单的看了看,本博客纯属记录学习过程,请大神们别笑,其中错误是难免的,毕竟是新手写的博客.下面就进入我们的正题吧,复习GUI时,就想 ...

  4. 使用VBScript实现设置系统环境变量的小程序

    本人有点桌面洁癖,桌面上只放很少的东西,很多软件都用快捷键调出.最近频繁用到一个软件,我又不想放个快捷方式在桌面,也不想附到开始菜单,于是乎想将其所在目录附加到系统环境变量Path上,以后直接在运行中 ...

  5. 调试台自动多出现一个'&#65279;' ,我 用uploadify上传图片时,在给页面写入一个返回值为图片名称的变量的值的时候值的前面始终多出现一个'&#65279;'

    对你有助请点赞,请顶,不好请踩------送人玫瑰,手留余香! 15:54 2016/3/12用uploadify上传图片时,在给页面写入一个返回值为图片名称的变量的值的时候值的前面始终多出现一个' ...

  6. java环境变量详细配置步骤

    1 下载jdk. a 官网:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 本来 ...

  7. JAVA基础篇NO1--环境变量的配置及命名规则

    标签(空格分隔): java基础 一:计算机概述 计算机:硬件和软件 硬件:控制器 运算器 存储器 输入和输出设备       存储器:外存(硬盘) 内存 软件:系统软件 应用软件   系统软件:wi ...

  8. 下载安装JDK,配置环境变量

    Hello,JDK; 在开始学习JAVA之前,第一件事情肯定是被告知:先下载JDK.就像我的一个朋友问我的一样"JDK是个什么鬼?我学的不是JAVA么,为什么要下载JDK?". J ...

  9. jdk安装及环境变量配置

    JDK是 Java 语言的软件开发工具包,主要用于移动设备.嵌入式设备上的java应用程序.JDK是整个java开发的核心,它包含了JAVA的运行环境,JAVA工具和JAVA基础的类库. jdk下载地 ...

随机推荐

  1. css 常用样式

    1. border-radius - 指定每个圆角 四个值: 第一个值为左上角,第二个值为右上角,第三个值为右下角,第四个值为左下角. 三个值: 第一个值为左上角, 第二个值为右上角和左下角,第三个值 ...

  2. [[4], [5, 6, 7]](Python)list的方法

    现在我们要学习一些Python的数据结构了,本节将主要学习列表(list)的用法 1.list的方法 list.append(x) 在list的末尾添加一个元素 >>> a=[1,2 ...

  3. [Chapter 3 Process]Practice 3.3 Discuss three major complications that concurrent processing adds to an operating system.

    3.3  Original version of Apple's mobile iOS operating system provied no means of concurrent processi ...

  4. css3 transform的基本用法和介绍

    <style>/* 最简单的一个transition动画 .box{width:100px;height:100px;border:1px solid;background:green;- ...

  5. MySQL之CAST与CONVERT 函数的用法

    两者具体的语法如下:CAST(value as type); CONVERT(value, type); 可以转换的类型是有限制的.这个类型可以是以下值其中的一个: 二进制,同带binary前缀的效果 ...

  6. .NET调用window串口读取电子秤的数据

    Private serialPort As SerialPort  '定义 Public Function CreateSerialPort() As String        Dim strWei ...

  7. window.opener强大功能

    window.opener后面的方法可以调用任意父窗口里面js的方法. eg.query()是父窗口的 function refreshParent(){   window.opener.query( ...

  8. 不均匀的Windows处理器编组

    不均匀的Windows处理器编组 之前写过一篇文章,关于SQLSERVER能识别多少个逻辑CPU的,前些天在论坛里有人问Windows处理器编组是如何划分的?? SQLSERVER到底能识别多少个逻辑 ...

  9. asp.net froms 移动平台(iphone 微信)无法存储的解决办法。

    更改form的默认设置,让系统不再根据设备来判断是否支持cookie 在站点的配置文件中有关于Form认证的配置,在配置<authentication mode="Forms" ...

  10. GitLab:解决Merge Request中Commits不更新的问题

    最近在使用 GitLab 的 Merge Requests 功能进行 Code Review .操作流程是这样的: 1)开发人员A要给一个项目增加一个新功能,先在这个项目上创建一个 Git 分支. 2 ...