在 C 语言的学习旅程中,变量、数据类型和常量是构建程序的基石。掌握这些基础知识,能够帮助我们更好地理解程序的运行机制,为后续的编程学习打下坚实的基础。本文将详细解读这些核心概念,结合实例代码进行说明,让大家能够清晰、准确地掌握相关知识。
数据类型:程序的 “数据容器”
C 语言的数据类型就像不同规格的容器,用来存储不同类型的数据。它们主要分为基本类型、构造类型、指针类型和空类型,其中基本类型是 C 语言内置的,使用最为广泛。
基本类型
基本类型是 C 语言直接提供的,包括整型、浮点型和字符型,每种类型都有其固定的字节大小,决定了能存储数据的范围。
整型:用于存储整数,根据字节大小不同又可分为以下几种:
- 短整型(short):占用 2 字节,能表示的整数范围相对较小。
- 基本整型(int):占用 4 字节,是日常编程中最常用的整型类型。
- 长整型(long):在 32 位系统中占 4 字节,在 64 位系统中占 8 字节,可存储更大范围的整数。
- 长长整型(long long):占用 8 字节,是 C99 标准新增的类型,能表示的整数范围更大。
浮点型:用于存储小数,根据精度和字节大小分为:
- 单精度型(float):占用 4 字节,精确到小数位 6 位,格式化输出符号为 % f。
- 双精度型(double):占用 8 字节,精确到小数位 15 - 16 位,格式化输出符号为 % lf。
- 长双精度型(long double):其字节大小取决于编译器,如 GCC 通常是 16 字节,MSVC 可能是 8 字节,能提供更高的精度。
字符型(char):C 语言中 1 字节等于 1 字符,由于没有专门的字节类型,所以常用 char 来表示字节,占用 1 字节。
我们可以通过 sizeof 运算符来查询变量或数据类型在当前编译系统中分配的存储空间大小,例如:
int a = 10;
printf("%d,%d\n", sizeof(int), sizeof(a));
// 输出结果为4,4,sizeof返回的大小以字节为单位,返回类型为long unsigned int
构造类型
构造类型是 C 语言提供构建语法,由程序员自己创建的类型,包括结构体(struct)、共用体或联合体(union)和枚举(enum),它们可以根据实际需求组合不同的基本类型,以满足复杂数据存储的需求。
指针类型
指针类型是 C 语言的一大特色,它用于存储变量的内存地址,通过指针可以直接访问和操作内存中的数据,在后续的学习中会详细介绍。
空类型(void)
空类型通常用于表示函数没有返回值,或者指针指向的类型不确定等情况。
常量:程序中不变的 “定值”
常量是程序运行过程中值不变的量,它们的存储位置由编译器决定,可能存储在数据段(字符串常量)或代码段。
常量的分类
- 整型常量:包括十进制整型常量、八进制整型常量和十六进制整型常量。十进制常量就是我们日常使用的整数,如 123;八进制常量以 0 开头,如 012;十六进制常量以 0x 或 0X 开头,如 0x12。
- 浮点型常量:有十进制表示法和指数表示法两种形式。十进制表示法如 3.14、10.0 等;指数表示法如 3.14e2( 表示 3.14×10² )、2E-3( 表示 2×10⁻³ )等。需要注意的是,字母 e 或 E 的前面必须有数字,后面必须为整数。
- 字符型常量:用单引号括起来的单个字符,如 ' A '、' b ' 等。
- 字符串常量:用双引号括起来的字符序列,如 " hello "、" C language " 等。
- 符号常量:通过宏定义来定义,使用 #define 指令,如 #define PI 3.14159,在程序中 PI 就代表 3.14159,提高了程序的可读性和可维护性。
变量:程序中变化的 “存储单元”
变量的概念
变量是在程序运行过程中值可变的量,它代表内存中(栈内存)具有特定属性的一个存储单元,用于存储数据。变量有一个名字,通过名字可以访问变量所存储的数据。
变量的定义与初始化
变量的定义格式为:数据类型 变量名列表。
变量的初始化是在定义变量时给它赋一个初始值,格式为:数据类型 变量名 = 初始化值。
以下是一些变量定义和初始化的例子:
// 1. 声明变量并初始化
int age = 21; // 定义int类型变量age,并初始化为21
// 2. 先声明,再赋值
int count;
count = 10; // 给已声明的变量count赋值为10
// 3. 可以为多个变量定义同一类型,多个变量之间使用逗号分隔
int a, b = 10, c; // 定义了3个int类型变量,b初始化为10,a和c未初始化
需要注意的是,访问未初始化的变量不会报错,但此时变量空间中的数据是系统分配的随机值,不建议访问,这在 C 标准中属于 “未定义行为(UB)”。
变量的命名规范
- 变量名由字母、数字和下划线组成,且必须以字母或下划线开头。
- 不能与 C 语言的关键字(如 if、int、float 等)或预定义标识符(如 printf、main、scanf 等)重名。
- 编译系统对字母的大小写敏感,如变量名 count 和 Count 是两个不同的变量。
- 变量名和函数名一般用小写字母 + 下划线,常量名和枚举名一般用大写字母 + 下划线,以提高代码的可读性,如变量 set_count、常量 SET_COUNT。
变量的使用
在 C 语言中,要求对所用到的变量在使用前必须强制定义,即先定义,后使用。
一个类型说明语句可以同时定义多个同类型的变量,各个变量之间用逗号分隔;多个同类型的变量也可以用多个类型说明语句定义。两种方式各有优缺点:
// 写法1:一个类型说明语句同时定义多个同类型变量
// 优点:简洁;缺点:可读性较差
int a, b, c, d;
int a1 = 3, b1 = 4, c1 = 5, d1 = 6;
// 写法2:多个同类型的变量用多个类型说明语句定义
// 优点:可读性强;缺点:繁琐
int aa;
int bb;
int aa1 = 3;
int bb1 = 4;
整型数据的存储与运算
整型数据在内存中的存储形式
数据在内存中是以二进制形式存放的,整型数据在内存中是以补码的形式表示的。使用补码主要是为了统一加减法运算,使 CPU 可以使用同一套加法电路处理所有整数运算(包括正数和负数),同时消除了 + 0 和 - 0 的歧义,简化硬件设计。
- 正数的补码和原码(该数的二进制形式)相同。
- 负数的补码是将该数绝对值的二进制形式,针对数据位按位取反后加 1(即反码 + 1)。
例如,对于整数 10 和 - 18:
- 10 的原码、反码和补码都是 0000 0000 0000 0110。
- -18 的原码是 1000 0000 0001 0010,反码是 1111 1111 1110 1101,补码是 1111 1111 1110 1110。
有符号与无符号整型
- 有符号整型变量(如 int)可以存放正数、0 和负数,默认就是有符号数,等价于 signed int。
- 无符号整型变量(如 unsigned int)可以存放正数和 0,不能存放负数,定义时必须添加关键字 unsigned。
以 char 类型为例,有符号 char 的存储范围是 - 128~127,无符号 char 的存储范围是 0~255,它们在内存中的存储形式不同,有符号数的最高位为符号位(0 表示正,1 表示负),无符号数的所有位都表示数值。
整型变量的使用案例
#include <stdio.h>
int main(int argc, char *argv[]) {
int a, b, c, d; // 定义有符号整型变量
unsigned int u; // 定义无符号整型变量
// 赋值
a = 12;
b = -24;
u = 10;
c = a + u;
d = b + u;
printf("a + u = %d, b + u = %d\n", c, d); // 输出结果为a + u = 22, b + u = -14
return 0;
}
需要注意的是,计算机硬件支持加法运算,不支持减法运算,程序中的减法运算实际上是有负数参与的加法运算,比如 5 - 2 实际上是 5 + ( -2 )。
浮点型数据的存储
浮点型数据在内存中按照指数形式(IEEE 754 标准)存放,系统将一个浮点型数分成尾数部分和指数部分分别存放。
以单精度浮点数(float)和双精度浮点数(double)为例:
类别 |
字节数 |
符号位 |
指数位 |
尾数位 |
指数偏移量 |
单精度浮点数 |
4 |
1 位 [31] |
8 位 [30~23] |
23 位 [22~00] |
127 |
双精度浮点数 |
8 |
1 位 [63] |
11 位 [62~52] |
52 位 [51~00] |
1023 |
下面以 27.5f 为例,说明单精度浮点数在内存中的存放形式:
- 27.5f 的二进制为 11011.1。
- 转换为指数形式:11011.1 = 1.10111×2⁴。
- 指数:4 + 127 = 131,转换为二进制是 10000011。
- 尾数:10111,需要补够 23 位,右侧补 0,得到 10111000000000000000000。
- 符号位为 0(正数),所以 27.5f 在内存中的存储形式为符号位(0)+ 指数位(10000011)+ 尾数位(10111000000000000000000)。
浮点型数据转二进制的方法:
- 整数部分:采用辗转除 2 直到商为 0 为止,将每次的余数从后往前排列。
- 小数部分:采用辗转乘 2 直到整数位出现 1 且小数位为 0 为止,将每次的整数位从前往后排列,若乘不尽则根据内存大小保留相应位数。
字符型数据的存储与使用
字符型数据的存储
字符型变量用来存放字符常量,C 编译系统规定以一个字节的存储空间来存放一个字符。将一个字符常量存入一个字符变量,实际上是将该字符对应的 ASCII 码存入内存单元。例如,'A' 的 ASCII 码是 65,'b' 的 ASCII 码是 98,它们在内存中以二进制形式存储。
字符型数据的使用
由于字符数据在内存中的存储形式与整型数据类似,所以字符型数据和整型数据之间可以通用。一个字符数据既可以以字符形式输出(使用 % c),也可以以整数形式输出(使用 % d),还可以对字符数据进行算数运算,相当于对其 ASCII 码进行运算。
#include <stdio.h>
int main(int argc, char *argv[]) {
char c1, c2;
c1 = 'A';
c2 = 'b';
// 以字符形式输出,结果为c1 = A, c2 = b
printf("c1 = %c, c2 = %c\n", c1, c2);
// 以整数形式输出,结果为c1 = 65, c2 = 98
printf("c1 = %d, c2 = %d\n", c1, c2);
return 0;
}
利用字符型数据的这一特性,可以实现大小写字母的转换。例如,小写字母比对应的大写字母的 ASCII 码大 32,所以将小写字母转换为大写字母可以减去 32,将大写字母转换为小写字母可以加上 32。
#include <stdio.h>
int main(int argc, char *argv[]) {
char c1, c2;
c1 = 'm';
c2 = 'Y';
printf("转换前:%c, %c\n", c1, c2); // 输出结果为转换前:m, Y
// 转换
c1 = c1 - 32;
c2 = c2 + 32;
printf("转换后:%c, %c\n", c1, c2); // 输出结果为转换后:M, y
return 0;
}
总结
今天介绍了 C 语言中的变量、基本数据类型和常量等核心概念,包括它们的定义、存储形式、使用方法等。掌握这些知识是进行 C 语言编程的基础,在实际编程中,要根据数据的特点选择合适的数据类型,正确定义和使用变量与常量,以编写高效、可靠的程序。