C: 变量与数据类型

变量就像一个个贴了标签的盒子——每个盒子有名字、有类型,只能装对应种类的东西,装错了就会出问题。

1. 什么是变量

变量是程序中用来存储数据的命名内存空间。你可以把它想象成一个盒子:


2. 变量声明与初始化

(1) 声明变量

声明变量就是告诉编译器:我要用一个盒子,它叫什么名字、装什么类型的东西。

C
int age;
float weight;
char blood_type;

声明后,变量的值是未定义的(垃圾值),里面装的是内存中残留的随机数据。千万别直接使用未初始化的变量!

(2) 初始化变量

初始化就是在声明的同时给变量赋一个初始值:

C
int age = 20;
float weight = 65.5f;
char blood_type = 'A';

💡 最佳实践:始终在声明变量时就初始化,避免使用未定义的垃圾值。这是一个好习惯,能帮你避免大量难以排查的bug。

(3) 先声明后赋值

你也可以先声明,后赋值:

C
int age;
age = 20;

效果和声明时初始化一样,但两步写法更分散,容易在声明和赋值之间误用未初始化的变量。

(4) 同时声明多个同类型变量

C
int a = 1, b = 2, c = 3;

⚠️ 注意:不建议在同一行声明多个变量并初始化,可读性差。如果每个变量都有重要的初始值,建议分行写。


3. 变量命名规则

C语言对变量名有严格的规则:

必须遵守的:

建议遵守的:

命名 是否合法 说明
age 合法 简洁有意义
_count 合法 下划线开头
student_name 合法 snake_case风格
2nd_place 非法 数字开头
my-score 非法 含减号(会被当成减法)
int 非法 关键字
Age 合法但不建议 大写开头通常用于类型名

4. 基本数据类型

C语言的数据类型决定了变量占多少内存、能存多大范围的值、数据如何解读。C99的基本数据类型如下:

(1) 整数类型

类型 占用字节 取值范围(典型) 格式占位符
char 1 -128 ~ 127 %c%d
unsigned char 1 0 ~ 255 %u
short 2 -32768 ~ 32767 %hd
unsigned short 2 0 ~ 65535 %hu
int 4 -2147483648 ~ 2147483647 %d
unsigned int 4 0 ~ 4294967295 %u
long 4或8 平台相关 %ld
unsigned long 4或8 平台相关 %lu
long long 8 -9223372036854775808 ~ 9223372036854775807 %lld

💡 实际建议:日常编程用 int 就够了,需要更大范围用 long long,处理字符用 charshort 在现代平台上很少使用,因为 int 的效率通常更高。

⚠️ 注意:上表中 int 占4字节是大多数现代平台的情况,但C标准只要求 int 至少占2字节。实际大小取决于平台,用 sizeof 来确认。

(2) 浮点类型

类型 占用字节 有效数字 取值范围(绝对值) 格式占位符
float 4 6-7位 1.2e-38 ~ 3.4e38 %f
double 8 15-16位 2.2e-308 ~ 1.8e308 %lf
long double 8或更大 18+位 平台相关 %Lf

浮点数的精度有限,不能精确表示所有小数。例如:

C
float f = 0.1f;
printf("%.20f\n", f);
TEXT 📖 仅展示
0.10000000149011611938

0.1 在二进制中是无限循环小数,float无法精确存储。这是浮点数的固有特性,不是bug。

🔥 实用建议:需要小数时默认用 double,精度更高且现代CPU上运算速度不比float慢。只有在内存受限的嵌入式场景才优先用 float

(3) 字符类型

char 类型本质上是一个1字节的整数,只不过通常用来存储字符。字符在内存中以ASCII码存储:

C
char ch = 'A';
printf("%c\n", ch);
printf("%d\n", ch);
TEXT 📖 仅展示
A
65

'A' 的ASCII码是65,用 %c 输出字符,用 %d 输出整数。这说明字符和整数在C中是相通的。

⚠️ 字符 vs 字符串'A' 是字符(单引号),"A" 是字符串(双引号,末尾有 \0)。两者完全不同,不能混用。

(4) _Bool类型

C99引入了 _Bool 类型,只能存储0和1。包含 <stdbool.h> 后可以用 booltruefalse

C
#include <stdbool.h>

bool is_valid = true;
bool is_empty = false;

5. sizeof运算符

sizeof 是C语言的关键字(不是函数),用来获取数据类型或变量占用的字节数:

▶ 示例

C
#include <stdio.h>

int main(void) {
    printf("char:   %zu bytes\n", sizeof(char));
    printf("short:  %zu bytes\n", sizeof(short));
    printf("int:    %zu bytes\n", sizeof(int));
    printf("long:   %zu bytes\n", sizeof(long));
    printf("long long: %zu bytes\n", sizeof(long long));
    printf("float:  %zu bytes\n", sizeof(float));
    printf("double: %zu bytes\n", sizeof(double));
    return 0;
}
▶ 试一试
TEXT 📖 仅展示
char:   1 bytes
short:  2 bytes
int:    4 bytes
long:   4 bytes
long long: 8 bytes
float:  4 bytes
double: 8 bytes

💡 %zusizeof 返回 size_t 类型,对应的格式占位符是 %zu。如果编译器不支持 %zu(某些旧版本),可以用 %lu 代替。

sizeof 也可以用于变量:

C
int age = 20;
printf("%zu\n", sizeof(age));

6. 格式化输出详解

(1) 整数格式化

C
int n = 42;
printf("十进制: %d\n", n);
printf("八进制: %o\n", n);
printf("十六进制: %x\n", n);
printf("大写十六进制: %X\n", n);
printf("带前缀八进制: %#o\n", n);
printf("带前缀十六进制: %#x\n", n);
TEXT 📖 仅展示
十进制: 42
八进制: 52
十六进制: 2a
大写十六进制: 2A
带前缀八进制: 052
带前缀十六进制: 0x2a

(2) 浮点数格式化

C
double pi = 3.141592653589793;
printf("默认: %f\n", pi);
printf("2位小数: %.2f\n", pi);
printf("8位小数: %.8f\n", pi);
printf("科学计数法: %e\n", pi);
printf("宽度12.2f: [%12.2f]\n", pi);
TEXT 📖 仅展示
默认: 3.141593
2位小数: 3.14
8位小数: 3.14159265
科学计数法: 3.141593e+00
宽度12.2f: [       3.14]

7. 类型取值范围

C标准库提供了头文件来查询各类型的取值范围:

(1) limits.h(整数类型)

C
#include <limits.h>

printf("int最小值: %d\n", INT_MIN);
printf("int最大值: %d\n", INT_MAX);
printf("char最大值: %d\n", CHAR_MAX);

常用宏:

含义
INT_MIN int的最小值
INT_MAX int的最大值
CHAR_MIN char的最小值
CHAR_MAX char的最大值
LONG_MAX long的最大值
LLONG_MAX long long的最大值

(2) float.h(浮点类型)

C
#include <float.h>

printf("float有效数字: %d\n", FLT_DIG);
printf("double有效数字: %d\n", DBL_DIG);
printf("float最大值: %e\n", FLT_MAX);

▶ 示例

▶ 示例

C
#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
    char ch = 'Z';
    int num = 100;
    float f = 3.14f;
    double d = 2.718281828;

    printf("char '%c' = ASCII %d, size = %zu\n", ch, ch, sizeof(ch));
    printf("int %d, size = %zu, range = [%d, %d]\n", num, sizeof(num), INT_MIN, INT_MAX);
    printf("float %.6f, size = %zu, digits = %d\n", f, sizeof(f), FLT_DIG);
    printf("double %.9f, size = %zu, digits = %d\n", d, sizeof(d), DBL_DIG);

    return 0;
}
▶ 试一试
TEXT 📖 仅展示
char 'Z' = ASCII 90, size = 1
int 100, size = 4, range = [-2147483648, 2147483647]
float 3.140000, size = 4, digits = 6
double 2.718281828, size = 8, digits = 15

▶ 示例

C
#include <stdio.h>

int main(void) {
    char lower = 'a';
    char upper = lower - 32;

    printf("小写: %c (ASCII %d)\n", lower, lower);
    printf("大写: %c (ASCII %d)\n", upper, upper);

    printf("\n数字字符:\n");
    char digit = '0';
    printf("字符 '%c' 的ASCII码 = %d\n", digit, digit);
    printf("字符 '%c' 的数值 = %d\n", digit, digit - '0');

    return 0;
}
▶ 试一试
TEXT 📖 仅展示
小写: a (ASCII 97)
大写: A (ASCII 65)

数字字符:
字符 '0' 的ASCII码 = 48
字符 '0' 的数值 = 0

💡 技巧:大小写字母的ASCII码相差32,小写减32得大写,大写加32得小写。数字字符 '0' 减去 '0' 可以得到它的整数值,这是字符转数字的基础。

❓ 常见问题

Q int和long long有什么区别?什么时候用long long?
A int通常占4字节,最大约21亿;long long占8字节,最大约922亿亿。当int范围不够时(如计算阶乘、大数运算),使用long long。日常编程int足够,不要盲目用long long,浪费内存且某些平台上运算更慢。
Q float和double该选哪个?
A 默认选double。double精度15-16位,float只有6-7位,精度差异巨大。现代CPU上double的运算速度与float几乎没有差别。只有在内存极度紧张的嵌入式设备上才优先选float。
Q char到底是有符号还是无符号?
A 取决于编译器和平台。C标准没有规定char是否有符号,编译器可以自行决定。如果需要确保符号性,请显式使用signed char或unsigned char。处理ASCII字符(0-127)时无所谓,处理大于127的值时必须明确。
Q 为什么不应该使用未初始化的变量?
A 未初始化的局部变量存储在栈上,其值是内存中残留的随机数据(垃圾值)。使用它会导致不确定行为——程序可能有时正常有时崩溃,且每次运行结果可能不同。这类bug极难排查,所以务必声明时就初始化。

📖 小节

📝 作业

  1. 编写程序,用sizeof输出你电脑上所有整数类型和浮点类型的字节大小,与你同学的结果对比,看看是否相同
  2. 编写程序,输出字母'a'到'z'的ASCII码值,每行5个,用%-5d格式对齐
  3. 计算并输出int类型的最大值+1的结果(整数溢出),观察输出并与INT_MIN对比,思考为什么
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏