1 初识变量
1.1 变量的意义
在程序设计中,变量是程序的基本组成单元,也是最基本的存储单位。它如同现实生活中的 “容器”,用于临时或长期保存各种类型的数据,为程序提供灵活的数据操作能力。
以选购小米 15 Ultra 手机为例,手机的各项配置(如外观、版本和购买方式等)都可以通过变量进行抽象表示:
外观:可用字符串变量表示,如 "黑色"、"白色"、"经典黑银"、"松柏绿"、"金棕色" 和 "鸢尾紫"。版本:可用组合数值变量表示,如 "12GB+256GB"、"16GB+512GB" 和 "16GB+1TB"。购买方式:可用字符串变量表示,如 "标准免息版"、"传奇典藏版影像套装" 和 "鎏金灰版影像套装"。
变量的存在使程序能够灵活地处理不同类型的数据,从而实现复杂的功能。
1.2 变量的本质
变量本质上是内存中的一块命名存储单元,用于存放程序运行期间可能发生变化的数据。
每个变量都包含以下三个核心要素:
数据类型:决定了变量可以存储的数据种类(如整数、浮点数、字符等),以及该数据在内存中所占的空间大小。变量名:是内存地址的抽象表示,通过变量名可以访问或修改变量所存储的值。值:变量当前所存储的具体数据内容,其值可以在符合数据类型的范围内进行更改。
在 C 语言中,变量名作为内存中特定存储单元的标识符,代表了该内存地址。每个变量在内存中都有唯一的地址,而变量名则是程序员用来访问和操作该地址数据的便捷方式。通过变量名,程序可以轻松地读取或修改变量的值,这是程序进行数据处理和逻辑运算的基础。
1.3 变量的声明与赋值
关键概念辨析
理解 “声明”、“定义”、“初始化” 和 “赋值” 这几个术语之间的区别和联系,对于准确掌握变量的使用至关重要。以下是对这些术语的具体解释:
声明变量:向编译器告知变量的类型和名称,但不分配具体值。例如,int a; 只声明了一个名为 a 的整型变量,但没有赋予它具体的值。定义变量:在 C 语言中,通常声明一个变量也意味着为其分配内存空间。因此,int a; 不仅是声明也是定义。不过,在某些上下文中(如函数原型),可能只是声明而不分配内存。初始化变量:在声明的同时给变量赋予初始值。例如,int a = 5; 不仅声明了变量 a,还将其初始化为 5。赋值变量:在变量已经被声明并分配内存之后,给它分配一个新的值。例如,a = 10; 是将已存在的变量 a 的值从原来的值更改为 10。
正确理解和区分这些概念有助于提高编程技能,避免混淆和错误,使代码更加清晰易懂。
声明与赋值规则
先声明后使用:变量必须先声明才能在程序中使用。声明与赋值方式:可以在声明变量之后单独赋值,也可以在声明时直接初始化。多变量声明:支持同时声明多个同类型变量,并可以选择性地初始化。值可变性:变量在其数据类型允许范围内可以动态改变其值。唯一性约束:在同一作用域内,变量名必须是唯一的,不允许重复声明。
案例演示
首先,在本地计算机上创建一个名为 “Chapter2_variable” 的文件夹,并使用 VS Code 打开该文件夹。随后,在此文件夹中新建一个名为 “var01.c” 的源文件。操作步骤如下:
然后编写如下代码:
#include
int main()
{
// 1. 先声明后使用:变量必须先声明才能在程序中使用
int a; // 声明变量 a,但未初始化
// 2. 声明与赋值方式:
// 2.1 可以在声明变量之后单独赋值
a = 10; // 给变量 a 赋值为 10
// 2.2 也可以在声明时直接初始化
int b = 20; // 声明变量 b 并初始化为 20
// 3. 多变量声明:支持同时声明多个同类型变量,并可以选择性地初始化
int c = 30, d, e = 40; // 同时声明多个整型变量,其中 c 和 e 被初始化,d 未初始化
d = 50; // 单独给变量 d 赋值
// 4. 值可变性:变量在其数据类型允许范围内可以动态改变其值
a = a + 5; // 将变量 a 的值增加 5
b = b - 10; // 将变量 b 的值减少 10
// 5. 唯一性约束:在同一作用域内,变量名必须是唯一的,不允许重复声明
// 下面的代码会导致编译错误,因为变量 b 已经在前面声明过
// int b = 999; // 错误:重复声明变量 b
// 变量未定义就使用:会导致编译错误
// f = 60;
return 0;
}
如果将上面示例代码中的 25 行和 28 行代码注释取消掉,编译器会提示错误,如下所示:
由此可见,在使用变量时,遵循声明与赋值的规范是一种良好的编程习惯,能让我们的编程之路更加顺畅。
2 输出变量:printf 的使用
2.1 基本用法
printf 是 C 语言中用于格式化输出文本的函数,名称来源于 "print formatted"(格式化打印)。该函数定义在
格式化字符串:格式化字符串是由双引号括起的字符串,包含两部分内容:普通字符和格式占位符。
普通字符:将按原样直接输出。格式占位符:用于指定对应数据的输出格式,由 % 和一个格式字符组成,例如 %d 表示输出一个整数。更多格式占位符将在后续内容中逐步介绍。
输出列表:输出列表是程序中需要输出的数据项,可以是常量、变量或表达式,它们将按照格式化字符串中格式占位符的顺序一一对应地进行输出。
2.2 案例演示
新建文件 “printf01.c”,然后编写如下代码:
#include
int main()
{
// 1. 先声明后使用:变量必须先声明才能在程序中使用
int a; // 声明变量 a,但未初始化
// 2. 声明与赋值方式:
// 2.1 可以在声明变量之后单独赋值
a = 10; // 给变量 a 赋值为 10
printf("变量 a 在单独赋值后的值: %d\n", a);
// 2.2 也可以在声明时直接初始化
int b = 20; // 声明变量 b 并初始化为 20
printf("变量 b 在初始化后的值: %d\n", b);
// 3. 多变量声明:支持同时声明多个同类型变量,并可以选择性地初始化
int c = 30, d, e = 40; // 同时声明多个整型变量,其中 c 和 e 被初始化,d 未初始化
d = 50; // 单独给变量 d 赋值
// 各个输出数据项将按照格式化字符串中格式占位符的顺序一一对应地进行输出
printf("变量 c: %d, 变量 d: %d, 变量 e: %d\n", c, d, e);
// 4. 值可变性:变量在其数据类型允许范围内可以动态改变其值
a = a + 5; // 将变量 a 的值增加 5
b = b - 10; // 将变量 b 的值减少 10
printf("变量 a 在修改后(+5)的值: %d\n", a);
printf("变量 b 在修改后(-10)的值: %d\n", b);
// 5. 唯一性约束:在同一作用域内,变量名必须是唯一的,不允许重复声明
// 下面的代码会导致编译错误,因为变量 b 已经在前面声明过
// int b = 999; // 错误:重复声明变量 b
// 解决方案:我们可以使用不同的变量名来避免重复声明
int num = 999; // 声明新的变量 num
printf("变量 num: %d\n", num);
return 0;
}
程序在 64 位 Windows 系统(VS Code 环境)中的运行结果如下:
3 输入变量:scanf 的使用
3.1 基本用法
scanf 是 C 语言中用于从标准输入(stdin,通常是键盘)读取数据并存储到已声明变量中的函数。该函数定义在
与 printf 类似,scanf 通过不同的格式占位符为不同类型的变量获取值。例如:
%d 用于读取整数。%f 用于读取浮点数。
更多格式占位符将在后续学习中详细介绍。
在使用 scanf 函数时,需要注意的是变量名前面需要添加 & 符号,即取地址符。这是因为 scanf 需要知道变量的内存地址,以便将输入的数据存储到该地址中。后续章节将详细讲解指针和取地址符的用法,进一步加深对 scanf 函数的理解。
3.2 案例演示
新建文件 “scanf01.c”,然后编写如下代码:
#include
int main()
{
// 声明一个整数变量 num
int num;
printf("请输入一个整数:");
// 从标准输入读取一个整数,并将其存储到变量 num 中
scanf("%d", &num); // 注意:变量名前面需要添加 & 符号
printf("您输入的一个整数是:%d\n\n", num);
// 声明三个整数变量 num1, num2, num3
int num1, num2, num3;
printf("请输入三个整数(使用空格分隔):");
// 从标准输入读取三个整数,使用空格分隔,并将它们分别存储到变量 num1, num2, num3 中
scanf("%d %d %d", &num1, &num2, &num3); // 注意:变量名前面需要添加 & 符号
printf("您输入的三个整数是:%d, %d, %d\n\n", num1, num2, num3);
return 0;
}
程序在 64 位 Windows 系统(VS Code 环境)中的运行结果如下:
4 关键字
关键字是 C 语言中具有特定含义的保留关键字,不能用作标识符(如变量名、函数名等)。随着 C 语言标准的演进,关键字的数量也逐步增加。
ANSI C(C89)标准包含 32 个关键字,C99 标准在此基础上新增了 5 个关键字,C11 标准进一步增加了 7 个关键字。如下所示:
类别ANSI C(C89)关键字C99 新增关键字C11 新增关键字控制语句关键字if,else,switch,case,default,do,while,for,goto,break,continue,return--数据类型关键字char,short,int,long,float,double,signed,unsigned,void_Bool,_Complex,_Imaginary_Atomic用户定义类型关键字enum,struct,union--存储类型关键字auto,extern,register,static-_Thread_local类型修饰符const,volatileinline,restrict_Alignas,_Alignof类型定义与操作typedef,sizeof-_Generic编译时控制关键字--_Static_assert,_Noreturn
控制语句关键字:用于控制程序的执行流程,包括条件判断(如 if,switch)、循环(如 for,while)、跳转(如 goto,break)、函数返回(return)等。数据类型关键字:用于定义变量的基本数据类型,如整型(int)、浮点型(float,double)、字符型(char)、空类型(void)等,也包括布尔型(C99 中 _Bool)和复数类型(C99 中 _Complex)等。用户定义类型关键字:用于定义用户自定义的数据结构类型,包括枚举(enum)、结构体(struct)和联合体(union),用于组织和管理复杂的数据结构。存储类型关键字:用于指定变量的存储类别和作用域,如自动变量(auto)、外部变量(extern)、寄存器变量(register)和静态变量(static),影响变量的生命周期和可见性。类型修饰符:用于对数据类型进行修饰,增强其语义或优化行为,如常量(const)、易变变量(volatile)、限制指针(C99 中 restrict)和内联函数(C99 中 inline)等。类型定义与操作:用于定义新的类型名或进行类型相关操作,如 typedef(定义类型别名)、sizeof(获取变量或类型大小)以及 C11 中的 _Generic(泛型选择表达式)。编译时控制关键字:用于在编译阶段进行检查或控制函数行为,如 C11 中的 _Static_assert(静态断言)和 _Noreturn(表示函数不会返回)。
💡 提示:
long long 是 C99 引入的标准整型,由两个 long 关键字组合而成,用于表示 64 位整数,但它本身不是关键字。
5 标识符
在 C 语言中,标识符(Identifier) 是用于命名变量、函数、数组、结构体、联合体、枚举等程序实体的字符序列。标识符是程序中用来唯一标识这些元素的名称。
5.1 强制命名规范
为确保代码的可读性、可维护性以及编译器的兼容性,C 语言对标识符的命名有以下强制性规范:
字符组成:标识符只能由英文字母(a-z, A-Z)、数字(0-9)和下划线(_)组成。开头字符:标识符不能以数字开头。例如:2sum 是非法的。不能是关键字:标识符不能与 C 语言的关键字重复。例如:int、if、return 等均不能作为标识符使用。大小写敏感:C 语言区分大小写,如 Hello 与 hello 被视为两个不同的标识符。长度限制:标识符的长度受编译器和平台限制,通常最多支持 63 个字符(具体以编译器说明为准)。
合法标识符示例:
a
BOOK_sun
MAX_SIZE
Mouse
student23
Football
FOOTBALL
max
_add
num_1
sum_of_numbers
非法标识符及其原因:
标识符错误原因$zj包含非法字符 $3sum以数字开头ab#cd包含非法字符 #23student以数字开头Foot-baii包含非法字符 -s.com包含非法字符 .b&c包含非法字符 &j**p包含非法字符 *book-1包含非法字符 -tax rate包含空格 don't包含单引号 '
5.2 推荐命名规范
除了强制规则外,为了提升代码的可读性和可维护性,推荐遵循以下命名风格规范:
使用有意义的单词:标识符应具有清晰的语义,使读者能够 “见名知意”。例如:sum、name、age、maxValue。多单词命名方式:
下划线分隔法(snake_case):使用下划线连接多个单词,如:max_classes_per_student。小驼峰命名法(camelCase):第一个单词小写,后续单词首字母大写,如:maxClassesPerStudent。
避免仅靠大小写区分:避免使用如 name 和 Name 这样仅靠大小写区分的标识符,容易引起混淆。避免以下划线开头的标识符:以 _ 开头的标识符通常被系统或库使用(如 C99 的 _Bool)。为避免命名冲突,建议开发者不要使用以下划线开头的标识符。
📚 扩展:大驼峰命名法和小驼峰命名法
在编程中,驼峰命名法(Camel Case) 是一种常见的命名风格,通过多个单词组合表达语义,且不使用空格或下划线,而是通过大小写变化来区分单词。根据首字母是否大写,分为两种形式:
大驼峰命名法(PascalCase)
规则:每个单词的首字母均大写,单词之间无分隔符。示例:UserName,CalculateTotal,StudentInfo。适用场景:常用于类名、结构体名、枚举类型名、函数名或方法名等具有 “命名主体” 意义的标识符。特点:
名称清晰直观,便于理解。在 C#、Java 等面向对象语言中,是类名和方法名的标准命名方式。
小驼峰命名法(camelCase)
规则:第一个单词首字母小写,后续单词首字母大写。示例:userName,calculateTotal,studentName。适用场景:适用于变量名、函数名、方法参数等局部标识符。特点:
写法简洁,便于快速阅读和输入。在 C、Java、JavaScript 等语言中被广泛使用。
⚠️ 注意:
保持一致性:同一项目或团队中应统一使用一种命名风格(如统一使用小驼峰或大驼峰),以提升代码的可读性和维护性。注重可读性:避免使用缩写或含糊不清的命名(如 usrNm 不如 userName 更直观)。遵循语言习惯:不同语言有不同的命名习惯:
C 语言:推荐使用小驼峰命名法命名变量和函数,也可使用下划线分隔法(如 max_value)。Java、JavaScript:推荐使用小驼峰命名变量和方法,大驼峰命名类名。C#、TypeScript:类名、接口、方法等使用大驼峰,变量和参数使用小驼峰。
💡 提示:
如果项目中已有命名规范,应优先遵循已有风格。使用 IDE 或代码格式化工具(如 clang-format)可以帮助自动统一命名风格。
6 编程实操
6.1 计算两个整数的和
编写一个 C 程序,定义两个整型变量,从键盘输入两个整数,计算它们的和并输出结果。
#include
int main()
{
int num1, num2, sum; // 定义两个整型变量用于存储输入,一个用于保存和
// 提示用户输入两个整数
printf("请输入两个整数(用空格分隔):");
// 使用 scanf 读取用户输入的两个整数
scanf("%d %d", &num1, &num2);
// 计算两个整数的和
sum = num1 + num2;
// 输出计算结果
printf("两个整数的和为:%d\n", sum);
return 0;
}
程序在 64 位 Windows 系统(VS Code 环境)中的运行结果如下:
6.2 交换两个整数的值
编写一个 C 程序,定义两个整型变量,从键盘输入两个整数,交换它们的值并输出结果。
#include
int main()
{
int num1, num2, temp; // 定义两个整型变量用于存储输入,temp 为临时变量
// 提示用户输入两个整数
printf("请输入两个整数(用空格分隔):");
// 读取用户输入并赋值给 num1 和 num2
scanf("%d %d", &num1, &num2);
// 输出交换前的值
printf("交换前的值:num1 = %d, num2 = %d\n", num1, num2);
// 使用临时变量交换两个数的值
temp = num1; // 将 num1 的值保存到 temp
num1 = num2; // 将 num2 的值赋给 num1
num2 = temp; // 将 temp(原 num1)的值赋给 num2
// 输出交换后的值
printf("交换后的值:num1 = %d, num2 = %d\n", num1, num2);
return 0;
}
程序在 64 位 Windows 系统(VS Code 环境)中的运行结果如下: