加载中...
从零接触C语言(初览)-II: 数据类型 和 变量

从零接触C语言(初览)-II: 数据类型 和 变量

周二 7月 08 2025
4199 字 · 19 分钟

数据类型 和 变量

在上一篇文章中, 我们运行了一个最简单的C语言程序:

C
#include <stdio.h>

int main() {
    printf("Hello World");
    
    return 0;
}

通过在main()函数中调用printf("Hello World");, 在终端中打印出来了Hello World

我们知道printf()是函数, 那么"Hello World"是什么呢?

在C语言中, 凡是被双引号""包裹的字符, 被称为字符串, 也叫字符串字面量

无论里面是英文字符、数字、符号, 甚至是中文字符, 只要被双引号括起来, 它就是一个字符串 :

  • "123""2.333""###""你好""Hello" 等等
  • 哪怕是一个字符, 如 "A"" ""9", 只要用双引号, 也是字符串
  • 甚至 "", 也表示一个合法的字符串, 称为空字符串

💡 但需要注意: 字符串其实是由一个个字符按顺序组合而成的, 比如

C
"Hello"'H' 'e' 'l' 'l' 'o'组成

C语言中, 单个字符通常使用单引号''包裹, 比如'A''1''%'

这些字符通常会存储为一种特定的数据类型: char类型

char类型之外, C语言中还有其他基本数据类型:

C
// 空类型
void
// 字符类型
char
// 短整型
short
// 整型(整数类型)
int
// 长整型
long
// 更长的整型
long long
// 单精度浮点数(单精度小数)
float
// 双精度浮点数(双精度小数)
double
// 扩展精度浮点数(不常用)
long double

这就是C语言中所有的基本数据类型了

你会发现, 这里边并没有字符串类型

实际上, C语言中字符串并不是一种基本数据类型, 字符串是由char类型字符按顺序组合成的

变量

C语言中, 你可以使用这些数据类型, 定义并使用变量

什么是变量?

从字面上看, “变量”就是可以变化的量, 即值会发生变化的数据

而在编程语言中, 并不是这么简单的, 不过可以 以一种简单的视角理解变量: 将变量, 当作一个有名字的”盒子”

这个盒子有特定的大小(由数据类型决定), 我们可以把数据放进去, 也可以随时拿到数据使用或替换成新的数据

变量的声明和定义

什么是变量的定义?

在C语言中, 变量 具体的定义方式是这样的:

C
char character = 'c';
int age = 20;
float weight = 55.5;
  • character是一个char类型的变量, 存储了字符 'c'
  • age是一个int类型的变量, 存储了整数20
  • weight是一个float类型的变量, 存储了浮点数 55.5

character age weight为不同类型、不同大小的变量, 把变量当成一个”盒子”来看, 这些盒子可以存储对应类型大小的数据, 这里的大小指的是bit(位)byte(字节)

变量的定义, 实际上就是创建这个具有大小的盒子的动作

变量定义之后, 这个具有一定大小的盒子就已经真正存在了

只有这个盒子真正存在了, 你才能使用这个盒子

除了定义之外, 还有一个概念是: 声明

定义是, 创建具有大小的盒子的动作, 可以使这个盒子真正存在

那么声明又是什么呢?

声明, 是声明一下有一个盒子, 但这个盒子是否真正存在, 则是未知的

如果你只声明变量, 这个变量是没有办法使用的

已经放在变量中的数据, 在之后的代码中, 就可以直接通过变量名来使用了, 比如:

C
#include <stdio.h>

int main() {
    int age1 = 18; // 变量age1, 放入数字18
    int age2 = 20; // 变量age2, 放入数字20
    printf("age1 加 age2 和为 %d\n", age1 + age2);

    return 0;
}

这段代码的执行结果为:

在C语言程序中, 不同的数据类型, 占用的大小是不同的, 这意味着”盒子”的大小不同, 即 变量的大小不同

每种类型的大小, 具体如下表所示:

数据类型占用大小
char1 byte
short2 byte
int4 byte
long4/8 byte(根据平台编译器的具体实现决定)
long long8 byte
float4 byte
double8 byte
long double8/16 byte(根据平台编译器的具体实现决定)
void不是用来存储数据的类型, 可以看作是一种空类型占位符, 不能用于定义变量

这些数据类型具体的大小占用, 也可以通过代码的形式在程序中打印出来:

C
#include <stdio.h>

int main() {
    printf("char size: %lu\n", sizeof(char));
    printf("short size: %lu\n", sizeof(short));
    printf("int size: %lu\n", sizeof(int));
    printf("long size: %lu\n", sizeof(long));
    printf("long long size: %lu\n", sizeof(long long));
    printf("float size: %lu\n", sizeof(float));
    printf("double size: %lu\n", sizeof(double));
    printf("long double size: %lu\n", sizeof(long double));

    return 0;
}

这段代码, 使用gcc main.c将其编译为可执行程序并运行的结果是:

可以看到打印结果是符合上面表格中的内容的

变量的命名规则

已经大概了解了, 变量可以简单理解为 程序中, 一个命名的有大小的存储数据用的盒子

不过, 变量命名也是有一定规则的, 并不是可以随便给变量命名

C语言标准中, 标识符(变量名、函数名等)的命名有一套明确的规则:

  1. 只能包含以下字符:

    • 字母: a-zA-Z
    • 数字: 0-9
    • 下划线: _

    标准中并未提及中文字符命名的相关规则, 但编译器可能支持

  2. 首字符必须是字母或下划线

    即, 首字符不允许是数字

  3. 区分大小写

    即, ageAge不属于同一标识符

  4. 禁止与关键字冲突

    即, 标识符的命名禁止与C语言中的关键字完全一致

    有关 关键字 并非本章介绍内容

下面是一些变量命名的正确例子和错误例子:

C
/* 正确例子 */
int age;
int Age;
float weight1;
double _theFloat;
double Double;

/* 错误例子 */
int 2age;    // 首字符禁止为数字
int float;    // 禁止与关键字完全一致
float the-weight;    // 非法字符
double $float;    // 非法字符

变量的分类 以及 作用域和生命周期

C语言程序的入口是main()函数

那么, 即使是最简单的C语言程序, 也会分出两种区域:

C
/*
入口外, 即 main() 函数外
*/
int main() {
    /*
    入口内, 即 main() 函数内
    */
    return 0;
}
/*
入口外, 即 main() 函数外
*/

在之前的例子中, 变量都是在main()函数内部定义的

那么, 变量可以在main()函数外部定义吗?

答案是可以

C语言中, 变量可以在main()函数外部定义

并且, 定义在main()函数内部和外部的变量, 是有一定区别的:

  1. main()函数外部定义的变量, 被称为全局变量

    在函数内部定义的变量, 被称为局部变量

  2. 全局变量的作用域, 一般为整个C 程序

    局部变量的作用域, 则只在定义局部变量所在的范围

    什么是变量的作用域?

    C语言中, 变量的作用域, 就是变量能被使用的有效范围

    比如, 在main()函数内定义的变量, 那这个变量的作用域就在main()函数的范围内, 出了main()函数就无法再使用

    实际上, 在C语言中一个{}声明一个代码块, 在代码块内定义变量, 此变量的作用域即为所在代码块

  3. 全局变量的生命周期, 为整个C 程序

    局部变量的生命周期, 为定义局部变量所在的范围

    变量的生命周期, 可以简单理解为变量的存活时间

    变量的生命周期, 一般是从变量完成定义到其所在作用域结束

  4. 全局变量和局部变量可以同名, 但在使用上 遵循就近原则

以实际的代码为例子:

C
#include <stdio.h>

int globalVar = 10; // 全局变量
int var = 20;        // 全局变量

int main() {
    printf("globalVar: %d\n", globalVar);
    printf("var: %d\n", var);

    int var = 30; // 局部变量
    printf("var: %d\n", var);

    {
        int _var = 40;
        int var = 50;
        printf("_var: %d\n", _var);
        printf("var: %d\n", var);
    }

    // printf("_var: %d\n", _var);
    printf("var: %d\n", var);

    return 0;
}

这段代码定义了很多个变量, 可以先来看一下执行结果:

我们可以结合现象, 分析一下每一句printf()所使用的变量是哪一个:

序号调用语句打印值值对应变量名是否有重名变量实际使用变量
17行: printf("globalVar: %d\n", globalVar);10globalVarglobalVar(第3行)
28行: printf("var: %d\n", var);20varvar(第4行)
311行: printf("var: %d\n", var);30varvar(第10行)
416行: printf("_var: %d\n", _var);40_var_var(第14行)
517行: printf("var: %d\n", var);50varvar(第15行)
621行: printf("var: %d\n", var);30varvar(第10行)

从结果来看, 可以分析出一些特性:

  1. 全局变量和局部变量可以重名

    编译没有问题, 运行也没有问题

  2. 变量的使用, 遵循就近原则

    即, 如果存在重名变量, 使用时 会使用已经定义的, 离调用位置近的变量

    在例子中表现为:

    局部变量var没有定义时, 使用var变量, 实际使用的是全局变量var

    局部变量var定义后, 使用var变量, 实际使用的是局部变量var

  3. 变量只在其作用域内生效

    即, 变量出了其作用域, 其生命周期就会结束, 无法再使用

    在例子中的表现为:

    17行打印的var值是50, 而第21行打印的var值是30

    如果把第20行代码的注释解开(删掉//), 编译会报错:

    报错信息为: _var未声明


总结来讲, 究竟什么是变量?

变量是一个命名的存储单元, 它可以用来存储程序运行过程中可能发生变化的数据

它有: 名字(标识符)、类型(数据类型决定它能存什么数据)、大小(由类型决定)、作用域(在哪能访问)、生命周期(存在多久)

还有这些特点:

  1. 类型明确: 每个变量都有明确的数据类型(如 intfloat 等)

  2. 内存占用不同: 不同类型的变量占用不同的字节数

  3. 命名有规则:

    只能由字母、数字和下划线组成, 且不能以数字开头

    不能与C语言中的关键字完全一致

  4. 作用域限制:

    全局变量在程序内全局有效

    局部变量只能在其定义的代码块中有效.

  5. 生命周期不同:

    局部变量: 随函数或代码块执行完毕而消失

    全局变量: 存在于整个程序生命周期

  6. 支持赋值与修改: 变量可以在程序中多次赋新值

  7. 使用需先定义: C语言要求变量在使用前必须先定义

const修饰变量

const是C语言标准中的一个关键字, 它是单词constant(常量)的简写

const常用于定义不可变的变量

在变量定义时, 将const放在类型前面, 表示该变量不能被修改(即只读), 也就是说, const修饰的变量在程序中不能被重新赋值

来看下面的代码:

C
#include <stdio.h>

int main() {
    int var = 10;
    const int con = 20;
    /*
    定义变量时, cosnt 放在类型前 修饰变量
    */

    printf("var: %d\n", var);
    printf("con: %d\n", con);

    return 0;
}

这段代码将会输出如下结果:

但是如果你试图修改con:

C
#include <stdio.h>

int main() {
    int var = 10;
    const int con = 20;
    con = 11;

    printf("var: %d\n", var);
    printf("con: %d\n", con);

    return 0;
}

那么, 编译就会发生报错:

报错信息为: 试图给只读变量con赋值

可以看到, const修饰的变量, 具有了常量属性, 无法修改, 只能读取


Thanks for reading!

从零接触C语言(初览)-II: 数据类型 和 变量

周二 7月 08 2025
4199 字 · 19 分钟