9 C 语言变量详解:变量本质与三大属性、声明与赋值规范、scanf/printf 用法、关键字分类、标识符命名规范

9 C 语言变量详解:变量本质与三大属性、声明与赋值规范、scanf/printf 用法、关键字分类、标识符命名规范

1 C 语言变量基础

1.1 变量的作用

在 C 语言中,变量(Variable)是用来存储和操作数据的基本单位。可以将变量看作程序中的 “数据容器”,它能在程序运行时保存不同的数据,并允许程序根据需要随时读取或修改这些数据。

在编写程序时,常常需要让计算机保存一些信息,比如用户输入的分数、传感器的温度值、商品的价格,或者某个操作的计数值等。如果没有变量,程序就无法记住这些变化的数据,也就无法进行后续的计算、判断或控制操作。

通过变量,程序不仅仅是按顺序执行固定的指令,而是可以根据不同的输入和程序状态,做出不同的反应。比如,根据用户的输入决定显示不同的内容。

因此,变量的作用是为程序提供一个可命名的数据存储空间。帮助程序动态地保存、处理和操作这些数据,确保程序能够灵活地响应外部变化。

1.2 变量的三大基本属性

每个变量都具备三大基本属性:数据类型(Type)、变量名(Name)和变量值(Value)。

这三个属性共同决定了变量的表现形式、可操作范围以及其在内存中的实际意义。

数据类型(Type):

决定变量可以存储的数据种类。例如:整型、浮点型、字符型、布尔类型等。决定变量在内存中所占的字节数。限定变量可执行的操作范围。例如:整型变量可进行算术运算;字符型变量主要用于字符与字符串处理。

变量名(Name):

又称标识符(identifier),用于在程序中唯一标识该变量。程序员通过变量名即可访问对应的内存空间,而无需关心其物理地址。变量名使代码更具可读性和可维护性,是程序逻辑与内存操作之间的抽象层。

变量值(Value):

指变量当前存储的数据内容。在程序运行过程中,变量的值可以被修改。修改必须遵循其数据类型的限制。例如:不可以将整型变量修改为字符串类型的数据。

1.3 变量的本质

在 C 语言中,变量本质上是一块被命名的内存空间,用于存储程序运行过程中可能变化的数据。

从标准术语来说,变量是一个 “具有名称的对象(object)” —— 也就是一段可用来保存值的数据区域。程序通过变量名访问这段内存,从而读取或修改其中的内容。

当程序被编译并运行时,编译器会为每个变量分配相应的存储空间,并建立变量名与内存地址之间的映射关系。程序员无需直接操作内存地址,而是通过变量名来间接访问数据。这种机制既让程序结构更清晰,也减少了直接操作内存所带来的复杂性与风险。

在程序的执行过程中,每个变量通常对应一块固定的内存区域(其地址在变量生命周期内一般保持不变),而变量名只是访问这块区域的符号化标识。程序通过变量名进行读写、计算和判断,从而实现各种逻辑功能。

简而言之:变量是程序访问内存中数据的抽象方式,它在 “逻辑世界” 和 “物理存储” 之间起到桥梁作用。

1.4 变量的声明与赋值

关键概念辨析

在 C 语言中,对变量的任何操作都始于它的声明与定义。要想编写正确、可维护的程序,必须准确理解以下四个密切相关的概念:“声明(Declaration)”、“定义(Definition)”、“初始化(Initialization)” 与 “赋值(Assignment)” 。它们共同描述了一个变量从被编译器识别到实际存储数据的完整生命周期。

声明(Declaration):

作用:告诉编译器变量的名称(标识符)和类型,使其在语法和类型检查阶段能正确识别该变量。内存分配:声明本身不一定分配内存空间,只有在同时也是定义的情况下才会分配。典型示例:extern int global_var;

该语句声明了一个名为 global_var 的整型变量,表示它在其他文件中已经被定义。这种 “仅声明不定义” 的方式,常用于多文件程序中共享全局变量。

定义(Definition):

作用:为变量分配实际的存储空间,并可选择性地赋初始值。定义同时也隐含声明的作用。内存分配:定义一定会分配存储空间。关系说明:所有定义都是声明,但并非所有声明都是定义。典型示例:int local_var;

该语句既是声明,也是定义。编译器会为 local_var 在栈上分配内存空间。

初始化(Initialization):

作用:在定义变量的同时,为其赋予一个初始值。这是变量生命周期中的第一次赋值操作。时机:初始化仅发生在变量被定义的那一刻。典型示例:int age = 18;

此语句在为 age 分配内存空间后,同时将 18 存入该空间。

赋值(Assignment):

作用:在变量已存在(已定义)之后,修改其存储的值。时机:可在程序运行期间的任意时刻进行,次数不限。典型示例:age = 20;

假设 age 已定义,该语句会用新值 20 覆盖其原有值。

核心区别总结:

概念主要作用是否分配内存示例声明告知编译器变量的名称和类型,使其在语法分析和类型检查阶段能够识别该变量。不一定

(仅声明存在,不保证分配空间)extern int a;定义为变量分配实际的存储空间,并可选择性地指定初始值。定义同时也具有声明的作用。是

(分配存储空间)int a;初始化在定义变量的同时,为其赋予一个初始值,是变量生命周期中的第一次赋值操作。是

(伴随定义发生)int a = 10;赋值在变量已存在(已定义)后,为其修改存储的值,将新数据写入已分配的内存中。否

(使用已有空间)a = 20;

声明与使用规则

在 C 语言中,变量的使用必须遵循一定的规则,以保证程序的正确性和可维护性。主要包括以下几个方面:

先声明(或定义)后使用:

在代码中引用一个变量之前,必须确保其声明或定义已经出现。否则,编译器无法识别该变量,编译时会报错。

作用域与名称唯一性:

作用域(Scope)定义了变量在程序中可见和可访问的范围。在同一作用域内(暂时可以简单理解为一个 { } 内),每个变量名称必须唯一。不同作用域可以定义同名变量,它们是独立的实体,互不干扰。

声明语法与初始化:

单独声明:先声明变量,稍后再赋值。声明时初始化:在声明变量时立即赋初值,可避免使用未初始化变量。多变量声明:同一类型的多个变量可以在一条语句中声明,用逗号分隔。

赋值与值的更新:

变量的 “可变” 特性体现在其值可以在程序运行期间通过赋值操作更新。赋值语句的执行过程:将右侧的值存入左侧变量对应的内存空间。变量的值必须遵循其数据类型规则,否则会产生类型不匹配错误。

2 输出变量:printf 函数

2.1 基本语法

printf 是 C 语言中用于将文本或变量值输出到屏幕的函数,其名称来源于 "print formatted"(格式化打印)。该函数定义在 头文件中,使用前必须包含该头文件,其基本语法如下:

格式化字符串:格式化字符串是由双引号括起来的文本,其中可以包含两类内容:

普通字符:程序会按原样输出普通字符,例如 "Hello, World!" 会显示为 Hello, World!。格式占位符:用于指定输出数据的格式,由 % 符号加上一个字符组成。例如:

%d 表示输出整数。%f 表示输出浮点数。%c 表示输出单个字符。%s 表示输出字符串。更多格式占位符将在后续章节中详细介绍。

输出列表:输出列表是对应格式占位符的值,可以是常量、变量或表达式。输出时,这些值会按照格式占位符在格式化字符串中出现的顺序依次对应。

2.2 案例演示

首先,在本地计算机上创建一个名为 Chapter2_Variable 的文件夹,并使用 VS Code 打开该文件夹。在此文件夹中新建一个名为 01output_variable.c 的 C 源文件,作为本次案例演示的代码文件,如下所示:

在 01output_variable.c 中输入如下示例代码:

#include

int main(void)

{

// 1. 先声明(或定义)后使用

// 在使用变量之前,必须先声明或定义变量,否则编译器无法识别

int a; // 声明变量 a

a = 10; // 赋值操作

printf("规则1 - 先声明后使用:a 的值 = %d\n", a);

int b_use = 20; // 声明并初始化变量 b_use

printf("规则1 - 声明并初始化:b_use 的值 = %d\n", b_use);

// 2. 变量的唯一性

// 在同一作用域内(暂时简单理解为一个 { } 内),每个变量名称必须唯一

int x = 5; // 定义变量 x

// int x = 10; // 错误示例:同一作用域内重复声明会导致编译错误

printf("规则2 - 变量唯一性:x 的值 = %d\n", x);

// 3. 声明语法与初始化

// 3.1 单独声明

int age; // 仅声明

age = 18; // 后续赋值

printf("规则3 - 单独声明:age 的值 = %d\n", age);

// 3.2 声明时初始化(推荐)

int height = 175;

printf("规则3 - 声明并初始化:height 的值 = %d\n", height);

// 3.3 多变量声明

int p = 1, q = 2, r;

r = 3;

printf("规则3 - 多变量声明:p=%d, q=%d, r=%d\n", p, q, r);

// 4. 赋值与值的更新

age = 20; // 更新 age 的值

b_use = 30; // 更新 b_use 的值

printf("规则4 - 值的更新:age=%d, b_use=%d\n", age, b_use);

// 5. 错误示例(已注释)

// printf("%d\n", undeclared_var); // 错误示例:使用未声明的变量会导致编译错误

// int x = 50; // 错误示例:同一作用域内重复声明变量会导致编译错误

// age = "字符串"; // 错误示例:类型不匹配,int 变量不能赋值字符串

return 0;

}

程序运行结果如下(环境:Win64 + VS Code + MinGW-w64 UCRT):

如果取消上述示例代码中第 41 至 43 行的注释,再次运行程序,编译器将报错,因为程序尝试使用未声明的变量、重复声明同名变量或对变量进行类型不匹配的修改,如下所示:

由此可见,遵循变量的声明、初始化和修改规范是良好的编程习惯。养成这种规范,不仅可以避免编译错误,还能让代码更易于阅读和维护,使编程过程更加顺畅。

3 输入变量:scanf 函数

3.1 基本语法

scanf 是 C 语言中用于从标准输入设备(通常是键盘)读取数据,并将输入内容存入指定变量的函数。该函数定义在 头文件中,使用时需包含此头文件,其基本语法如下:

与 printf 类似,scanf 也使用格式占位符来指定输入的数据类型,例如:

%d 用于读取整数。%f 用于读取浮点数。%c 用于读取单个字符。%s 用于读取字符串。更多格式占位符将在后续章节中详细介绍。

使用 scanf 时,必须在变量名前加上 &(取地址符),这是因为 scanf 需要知道变量在内存中的具体位置,才能把用户输入的数据写入到那个位置。如果省略 &,程序将无法获得变量地址,可能导致输入失败或产生不可预期的错误。

3.2 案例演示

继续在 Chapter2_Variable 文件夹中新建一个名为 02input_variable.c 的 C 源文件,作为本次案例演示的代码文件,并在 02input_variable.c 中输入如下示例代码:

#include

int main(void)

{

int score1, score2, score3; // 用于存储三名同学的成绩

// 1. 录入成绩

printf("请输入三名同学的期中成绩(整数,用空格分隔):");

scanf("%d %d %d", &score1, &score2, &score3);

// 输出录入的成绩

printf("录入的成绩为:%d, %d, %d\n", score1, score2, score3);

// 2. 假设发现成绩录入有误,需要修改

printf("发现成绩录入有误,请修改第二名同学的成绩:");

scanf("%d", &score2); // 修改第二名同学的成绩

// 输出修改后的成绩

printf("修改后的成绩为:%d, %d, %d\n", score1, score2, score3);

return 0;

}

程序运行结果如下(环境:Win64 + VS Code + MinGW-w64 UCRT):

4 C 语言关键字

在 C 语言中,关键字(Keyword)是具有特殊含义、被语言保留使用的标识符。

程序员不能将关键字用作变量名、函数名或其他标识符,否则会导致编译错误。

随着 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)和复数类型(_Complex、_Imaginary),C11 新增原子类型(_Atomic)以支持多线程原子操作。用户定义类型关键字:用于定义自定义数据结构,包括枚举(enum)、结构体(struct)和联合体(union),帮助程序员更好地组织和管理复杂数据。存储类型关键字:用于指定变量的存储类别和可见范围,如:自动变量(auto)、外部变量(extern)、寄存器变量(register)、静态变量(static)。C11 新增 _Thread_local 用于线程局部存储,使不同线程拥有独立的变量副本。类型修饰符:用于修饰或限定数据类型,增强语义或优化行为:const(常量修饰)、volatile(防止编译器优化易变数据)、C99 的 restrict(限定指针)、inline(内联函数),C11 的 _Alignas 与 _Alignof(内存对齐控制)。类型定义与操作:typedef 用于定义类型别名,sizeof 用于获取类型或变量所占的字节数。C11 新增 _Generic,引入泛型选择表达式,可在编译期根据类型选择不同的表达式。编译时控制关键字:用于在编译阶段进行检查或指示函数特性:C11 引入 _Static_assert(静态断言)和 _Noreturn(表示函数不会返回)。

C23 标准的关键字更新

随着 C23 标准的发布,C 语言进一步完善了类型系统与关键字体系。部分旧关键字被替代为更符合现代 C 风格的新关键字,同时引入了更多高精度与通用性的数据类型。

已被替代或弃用的关键字

_Bool → bool_Alignas → alignas_Thread_local → thread_local这些替代关键字可提升代码可读性,并增强与现代 C 标准(如 C++)的兼容性。

C23 新增关键字

_BitInt:声明任意位宽的整数类型,支持定制位数整数。_Decimal32、_Decimal64、_Decimal128:引入十进制浮点类型,适用于高精度或财务计算。C23 的这些新增关键字大幅扩展了 C 语言在数值精度、可移植性与表达能力方面的能力,使其更适应现代应用场景。

💡 提示:long long 类型说明

long long 是 C99 标准引入的整型类型,由两个 long 关键字组合而成,用于表示至少 64 位的整数。需要注意的是,long long 本身不是单独的关键字,而是由两个关键字组合形成的类型标识符。

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 程序,实现以下功能:

定义两个整型变量用于存储用户输入的整数;提示用户从键盘输入两个整数,并使用 scanf 读取这两个值;计算两个整数的和,并使用 printf 将结果输出到屏幕;输出时给出明确的提示信息,让用户一目了然。

通过本练习,巩固变量定义、输入输出函数、基本运算以及 scanf 和 printf 的使用方法。

#include

int main(void)

{

int num1, num2; // 用于存储用户输入的两个整数

int sum; // 用于存储两个整数的和

// 提示用户输入两个整数

printf("请输入两个整数(以空格分隔):");

// 读取用户输入的两个整数

scanf("%d %d", &num1, &num2);

// 计算两个整数的和

sum = num1 + num2;

// 输出计算结果

printf("您输入的两个整数分别是 %d 和 %d,它们的和为 %d。\n", num1, num2, sum);

return 0;

}

程序运行结果如下(环境:Win64 + VS Code + MinGW-w64 UCRT):

6.2 交换两个整数的值

编写一个 C 程序,实现以下功能:

定义两个整型变量,用于存储用户输入的两个整数;从键盘输入这两个整数;使用临时变量 temp 交换两个整数的值;输出交换前和交换后的整数值,以便学习者清楚看到交换的效果。

通过本练习,掌握变量定义、输入函数 scanf 的使用,以及使用临时变量进行数据交换的方法,强化对变量操作和数据存储的理解。

#include

int main(void)

{

int num1, num2; // 存储用户输入的两个整数

int temp; // 临时变量,用于交换两个数的值

// 提示用户输入两个整数

printf("请输入两个整数(用空格分隔):");

// 读取用户输入的两个整数

scanf("%d %d", &num1, &num2);

// 输出交换前的数值

printf("交换前的值:num1 = %d, num2 = %d\n", num1, num2);

// 使用临时变量进行交换

temp = num1; // 保存 num1 的值

num1 = num2; // 将 num2 的值赋给 num1

num2 = temp; // 将 temp(原 num1 的值)赋给 num2

// 输出交换后的数值

printf("交换后的值:num1 = %d, num2 = %d\n", num1, num2);

return 0;

}

程序运行结果如下(环境:Win64 + VS Code + MinGW-w64 UCRT):

相关推荐