Home

cdeveloper

读书,写作

从 0 学习 C 语言系列:对「变量」的完整理解


版权声明:本文为 cdeveloper 原创文章,可以随意转载,但必须在明确位置注明出处!

今天给大家分享的是 C 语言中非常重要的基础知识「变量」,因为写程序时时刻刻都要用到变量,所以非常有必要完整地了解它,学习的时候不要看不起这些基础的东西,要知道「勿以浮沙筑高台」,打好基础比啥都重要。

什么是变量?

变量是指:「常驻在计算机内存中需要经常改变的数据」。我们在程序中定义一个变量,在程序运行时该变量在内存中有一个独立的地址,改变变量的值就相当于重写该地址中的内容。

那如何定义一个变量呢?以定义整型变量为例:

int a = 0;

该定义表示:变量 a 是一个整型变量,顾名思义用来存储整数,且初始值为 0。

什么常量?

类比变量不难知道,常量就是:「常驻在内存中不变的数据」。因为当你打算定义一个常量的时候,你是不希望以后再改变它的。

那又如何定义一个常量呢?在 C 中有两种方法:

1. define 宏定义

例如,定义常量 PI:

#define PI 3.14159

要注意,该定义将 PI 定义为一个「符号」,而不是一个变量,在程序中只起到「替换作用」,所以其在内存中没有地址。在编译期间,编译器会用 3.14159 来替换程序中的符号 PI,但是要注意替换过程中的副作用。

2. const 关键字

使用 const 关键字来修饰一个变量,使其成为常量,以此来告诉编译器其值不可改变,使用方法如下:

const int b = 1;

如果在该定义之后尝试修改变量 b,则编译器会报错。

变量的内存机制

我以下面这个例子来解释下变量在内存中是如何存储的:

#include <stdio.h>

int main(void) {
  int A = 65;
  printf("%c memory address = 0x%X", A, &A);

  // 调试:这里打断点
  getchar();
  return 0;
}

在 vs2013 中调试运行,记得打断点,运行结果输出变量 A 的内存地址,每个人的输出结果可能都不同,我的如下:

A memory address = 0x45FC34

我们调出内存窗口:「工具栏 -> 调试 -> 窗口 -> 内存 -> 内存 1(1)」,然后输入变量 A 的地址,选择显示 1 列,右击选择显示 4 字节整数(int),得到下面的信息:

memory

可以看到这一行:

0x0045FC34  00000041  A...

其中:

  1. 0x0045FC34 是 A 的内存地址
  2. 00000041 是 65 的 16 进制表示
  3. A… 分别表示 41 00 00 00

那你可能会问了,00000041 A… 为什么是反的?我们再在内存窗口右击选择 1 字节整数显示,得到下面的信息:

memory2

现在看的是不是对上了,其实这跟计算机的字节序有关,这里补充下字节序列的定义:

  1. Little endian 小端:低位字节存储在低位地址
  2. Big endian 大端:高位字节存储在低位地址

例如,在内存中存储 0x01020304 的 2 种方式,括号中是内存地址 0x1000 - 0x1003:

  • 小端存储:04(0x1000) 03(0x1001) 02(0x1002) 01(0x1003)
  • 大端存储:01(0x1000) 02(0x1001) 03(0x1002) 04(0x1003)

搞清楚后不难得出,「我的机器是小端字节序」,因为低位字节 0x41 存储在低位地址 0x0045FC34。

通过这个简单的分析,我们就了解了一个变量在内存中的存储方式。如果你是新手,建议你「一定要自己调试这个过程」,一定会有很大收获的。对了,如果不了解计算机内存,目前就把它看做一个「字节数组」即可,以后等你牛逼了再好好学习内存的相关知识。

定义变量时要初始化

定义变量时最好养成好习惯,为其初始化一个值,如果没有指定值,那就初始化为 0。如果没初始化,而恰好后面又使用了这个变量,那么在 vs 中会编译失败,例如下面这个程序:

#include <stdio.h>

int main(void) {
  int x;
  printf("x = %d", x);
  return 0;
}

编译错误信息:

main.c(5): error C4700: 使用了未初始化的局部变量「x」

没有初始化的变量,默认值是垃圾数据,在 VS 中使用变量前必须初始化,使用其他编译器的同学,自行调试看结果。

关于命名规则

变量的命令规则没有谁错谁对,选择适合你的就行,或者公司有强制规定,那就遵守吧。我经常使用的命名规范是「Google C++ 开源项目的编程规范」,你可以参考使用。

欢迎关注我的公众号:「cdeveloper」

cdeveloper at 05/12/18