注解一:变量

Warning

在部分代码中,我会省略例如 int main() #include <stdio.h> 这样的“框架”代码。

正如前文所说,我们用编程语言来描述解决问题的办法,这个过程就是所说的写代码或者说编程。

既然要解决问题,就需要存储数据,需要描述怎么算出答案。在C语言中,存储数据的东西就是变量,描述计算过程的就是语句。

变量就像人类计算时写在草稿纸上的草稿,语句则是人类计算的方法(存在大脑中)。

有一个很有名的一句话便是:

程序=算法+数据结构

其中,算法就是由语句构成,数据结构就是由变量构成,可见变量和语句的重要性。

变量名 #

变量的数据存储在内存中,通过变量名进行访问。

抛去底层的细节,我会以不准确的比方来为变量注解。

在下面,我会将内存比作具有奇怪书写规则的草稿本,变量名比作页码,变量值比作草稿本上的数字。

试想象,有一个能够无限次数擦写的草稿本,但是规定是每一页草稿纸只能写一个数,该如何使用这个草稿本来存储数据?

我们可以把数字写在草稿本上,然后把页号记下来,在需要查询数据的时候翻到对应页数上,就像查电话簿那样。

但是这样子的话,我们写出来的计算过程也许会是这样:

取出草稿本上第 1 页的数字

取出草稿本上第 2 页的数字

将前面两个数字相加的结果存储在第 3 页的数字上

取出草稿本上第 3 页的数字

取出草稿本上第 4 页的数字

将前面两个数字相加的结果存储在第 5 页的数字上

取出草稿本上第 5 页的数字

将前面一个数字乘以 0.2 的结果存储在第 6 页的数字上

输出第 6 页的数字

看着会莫名其妙,你知道它在进行一些数学计算,但是却看不懂实际的意思。因为页码只是一个数字,而没有名字。

所以我们需要给草稿本上的数字取一个名字,这样子我们只需要记名字就行了,关于根据名字找到数字的过程,计算机自己会帮我们完成。

将上面的例子改成用名字来当查数据的页码,我们就可以这样写:

取出草稿本上 商品成本 页的数字

取出草稿本上 运输费用 页的数字

将前面两个数字相加的结果存储在 基本成本 页的数字上

取出草稿本上 基本成本 页的数字

取出草稿本上 营销费用 页的数字

将前面两个数字相加的结果存储在 总成本 页的数字上

取出草稿本上 总成本 页的数字

将前面一个数字乘以 0.2 的结果存储在 定价 页的数字上

输出 定价 页的数字

这下看懂了。

这实际上是一个“根据商品成本计算商品最终定价”的算法。

将草稿本换回内存,页码换回变量名,数字换回变量值,我们可以知道 C 语言中的变量名是什么作用:给电脑的草稿本,也就是内存中的某一页起一个名字,方便我们查询和修改。

上面的例子在 C 语言中则是这样(虽然按照规范变量名应该使用英文,但是在这里使用中文便于理解):

#include <stdio.h>

int main() {
    double 商品成本 = 100.0;
    double 运输费用 = 10.0;
    double 基本成本 = 商品成本 + 运输费用;
    double 营销费用 = 20.0;
    double 总成本 = 基本成本 + 营销费用;
    double 定价 = 总成本 * 0.2;

    printf("商品定价为 %.2f\n", 定价);

    return 0;
}

如果涉及到你不会的语法比如说return, %.2f之类的,你可以不去理会,只需要基本的变量定义和运算语法就足够了。

上面的变量名在我们的程序被转换成0101的二进制语言时会被替换成内存草稿本上具体的数字,电脑程序运行时则会根据具体的数字去读写数值。

Tip

如果变量名乱写,那变量名本身的存在就没意义了。

所以写一个好的、清晰的、能够让人理解的变量名是非常重要的,并且是规范之一。

变量类型 #

变量类型没什么好说的,在上面的例子,草稿本上只是直接写了数字,而变量类型的作用就是告诉电脑该怎么计数。

一个例子便是,人类可以直接写0~9的数字来记整数,但是电脑底层是二进制的,所以在内存中存储的变量是二进制的0101,在 C 语言中,如果是 int 类型的变量,在内存中则会用32位二进制数来存储;而如果是 double 类型的变量,在内存中则会用则会用64位二进制数来存储。(不准确的说法,但是不妨碍理解)

整数、小数在内存中的存储方式都是不同的,因此变量类型要写对,如果以错误的变量类型读取了内存中存储的数据,就会出现很奇怪的数。(在学习指针之后,这个现象会更常见)

下面这个例子展示了错误的变量类型会导致的错误:

#include <stdio.h>

int main() {
    int a = 5;
    double b = 5;
    int c = 2;

    printf("a / c = %d\n", a / c); // 2.0
    printf("b / c = %f\n", b / c); // 2.5

    return 0;
}

为什么a / c的结果是2.0而不是2.5呢?

因为aint类型,这是一个整数类型,在算除法的时候计算机会把计算结果中的小数部分忽略掉,就算结果是2.5,也会把小数位后面的数抹去,变成2

bdouble类型,这是一个浮点数类型,在算除法的时候计算机会保留计算结果中的小数部分,所以结果是2.5

这就是为什么a / c的结果是2.0,而b / c的结果是2.5

可见,变量类型告诉了计算机怎么在内存记数据,以及怎么算数据,不同的类型存储和计算的方式不一样,结果也会不一样。

更多以及可能的误区 #

关于变量的更多细节,其实没什么需要复述的,大部分教程都会提及,你可以检查是否理解下面这些问题:

在 C 语言中:

  • 变量名是什么?
  • 有多少变量类型?分别是什么?
  • 如何声明一个变量?
  • 如何修改变量的值?
  • 如何使用变量?

如果你能理解这些问题,那么变量就没什么问题了。

如果不能理解,我猜你可能是卡在了这个误区:等于号。

特别需要说明,C 语言的=不是数学中的等于号,而是赋值符号,意思是将右边的数值赋给左边的变量,也就是让左边变量的值改变为右边的值。

之所以这么说,是因为=并不会改变右边的值,而只是将右边的值赋给左边的变量,所以=并不是数学中的等号。

为了脱离误区,尝试把这个当成一个动作,而不是一个数学结论,或许能更好理解。

或者将=想象成<-左箭头,或许也可以避免不自觉误解成等于号。