什么是标识符、关键字和预定义标识符
标识符:用于给变量、函数、数组、结构体、宏等程序元素命名。
命名规则:
1.由字母(A-Z、a-z)、数字(0-9)、下划线(_)组成,必须以字母或下划线开头(不能以数字开头)。
2.区分大小写。
3.不能与 C 语言的关键字重名(否则会导致语法错误)。
4.长度无严格限制,但编译器通常只识别前 31 个字符。
举例:
变量名:a、total、student 关键字:也叫保留字,是预先定义好的,有固定语法含义的单词,用来表示语言的核心结构(如数据类型(int,char…),控制流程(if,switch…),存储类型等),是C语言语法的一部分,不能用作标识符。 预定义标识符:是C语言中预定义好,具有特定功能的名称,主要包括标准库函数名(printf,scanf)和编译器内置宏(__FILE__,__LINE__等)。这与关键字不一样的地方在于它允许被用户重新定义,但不推荐这样做,会导致原有功能失效。
什么是语法检查和语义检查
语法检查(Syntax Checking):是对代码的结构和格式进行验证,确保其符合编程语言的语法规则。它仅关注代码的 “形式是否合法”,不涉及代码的实际含义。验证关键字、标识符、运算符、分隔符(如括号、分号、逗号)的使用是否符合语法规则(if后面是否带括号,语句结尾是否有分号)。检查语句结构是否完整(例如,for循环的三个表达式是否用分号分隔,函数调用的参数列表是否用括号包裹)。
确保代码的嵌套和层次关系正确(例如,括号是否匹配)。
错误示例 1:if a > 5(缺少括号,语法结构错误)→ 语法检查失败。 语义检查:是在语法检查通过后,对代码的含义和逻辑进行验证,确保其符合编程语言的语义规则。它关注代码的 “内容是否合理”。
1.验证变量、函数、类型的定义与使用是否一致(例如,使用未定义的变量,调用不存在的函数,函数参数类型 / 数量不匹配)。
2.检查运算的合法性(例如,整数除以字符串,数组索引为负数,对常量赋值)。
3.确保类型兼容(例如,将字符串赋值给整数变量,指针类型不匹配)。
4.验证控制流逻辑的合理性(例如,函数声明为int类型却无返回值,跳转语句指向无效位置)。
错误示例:int a; a = “hello”;(语法正确,但整数变量赋值字符串,类型不兼容)→ 语义检查失败。
什么表达式?什么是语句?什么是代码块?
表达式:是由操作数(变量、常量、函数调用等)和运算符(+、*、&&等)组合而成的代码片段,核心功能是 “计算并返回一个值”。
可嵌套:可作为其他表达式的一部分,形成更复杂的计算(如(a + b) * c中,a + b是子表达式)。
可能有副作用:部分表达式在计算时会改变程序状态(如赋值x = 5、自增i++) 语句:是用于执行特定动作的代码单元,它描述程序的行为(如定义变量、控制流程、修改状态等),核心功能是 “完成一个操作”,而非返回值。
特点:
无返回值:执行目的是产生 “动作”(如赋值、循环、分支),不返回可供后续使用的值(即使包含表达式,也聚焦于其 “副作用”)。
改变程序状态:可能修改变量的值(如int a = 5;)、控制执行流程(如if (x > 0) { … })或触发 I/O 操作(如printf(“hello”);)。
语法标志:多数语言中以分号(;)结尾 代码块(又称复合语句)是用特定符号(如{ })包裹的一组语句的集合,用于将多个语句视为一个整体,通常与控制流语句(if、for等)配合使用,明确动作的范围。
特点:
整体性:内部的多个语句被当作一个单元执行,常用于控制流语句的 “作用域”(如if的条件满足后执行的所有语句)。
作用域隔离:部分语言中,代码块内定义的变量仅在块内有效(如 C 语言中{ int a = 5; },a无法在块外访问)。
嵌套性:代码块可以嵌套,形成多层结构
什么是左值、右值、对象、副作用、未定义行为?
左值:最初指 “可以出现在赋值表达式左侧的值”,在 C/C++ 中更准确的定义是:表示一个 “对象” 或 “函数” 的表达式,具有可标识的存储位置(地址),可以被取地址(& 运算符),且能被赋值 (除非是 const 修饰的左值)。
特点:
有明确的内存地址,可被修改(非 const 情况下)。
可以出现在赋值运算符的左侧或右侧。 右值:指 “只能出现在赋值表达式右侧的值”,是不具有持久存储位置的临时值或字面量,通常是表达式计算的结果,无法被取地址(& 运算符对右值无效),也不能被赋值。
特点:
没有稳定的内存地址(或地址不可访问),是临时的、一次性的。
只能出现在赋值运算符的右侧。 对象:是 “占据内存中一块区域的数据存储”,可以是变量、数组元素、结构体成员等,本质是 “内存中的一块空间”,用于存储数据(数值、字符、指针等)。
特点:
有明确的内存地址和大小(由类型决定,如int对象占 4 字节)。
与 “值” 相对:对象是存储位置,值是对象中存储的内容 副作用:指表达式或语句在计算值之外对程序状态产生的修改,通常表现为修改对象的值、输入 / 输出操作(I/O)、修改文件等。
核心:改变程序的 “可见状态”:
修改变量的值(如a = 5;、i++)。
进行输入(scanf)或输出(printf)。
动态内存分配 / 释放(malloc、free)。
调用影响外部状态的函数(如修改全局变量的函数) 未定义行为:指编程语言标准未规定其执行结果的代码行为,即编译器 / 运行时对这类代码的处理是 “任意的、不可预测的”,可能导致程序崩溃、结果错误、甚至安全漏洞。
产生原因:
C/C++ 等语言为追求高性能,允许编译器对未定义行为做任意优化,因此标准不保证这类代码的执行结果。
什么是结合性、左结合、右结合?
结合性(Associativity) 是运算符的重要特性之一,用于解决相同优先级的运算符连续出现时的计算顺序问题。当多个优先级相同的运算符组成表达式时,结合性决定了运算从左到右还是从右到左执行。
结合性的核心作用
当表达式中存在多个优先级相同的运算符时,优先级无法确定计算顺序,此时由结合性决定执行方向。例如:
表达式 a - b - c 中,两个 - 优先级相同,结合性决定是先算 (a - b) 还是 (b - c)。
左结合:(又称左到右结合)指相同优先级的运算符从左到右依次计算,即先处理左边的运算符,再处理右边的。
常见左结合运算符(以 C 语言为例):
算术运算符:+(加)、-(减)、*(乘)、/(除)、%(取余)
关系运算符:==(等于)、!=(不等于)、<(小于)、>(大于)、<=(小于等于)、>=(大于等于)
逻辑运算符:&&(逻辑与)、||(逻辑或)
逗号运算符:, 右结合:(又称右到左结合)指相同优先级的运算符从右到左依次计算,即先处理右边的运算符,再处理左边的。
常见右结合运算符(以 C 语言为例):
赋值运算符:=、+=、-=、*=、/= 等
单目运算符:++(后置自增除外)、–(后置自减除外)、&(取地址)、*(解引用)、!(逻辑非)等
条件运算符:?:(三目运算符)
指针成员运算符:->*、.*