在嵌入式面试中,C 语言基础是重中之重。本文针对经典面试题进行详细解析,帮助新手系统掌握知识点,提升面试应对能力。
在数据结构中,从逻辑上可以把数据结构分为( )。
A、动态结构和静态结构
B、紧凑结构和非紧凑结构
C、线性结构和非线性结构
D、内部结构和外部结构
在数据结构中,逻辑结构描述的是数据元素之间的逻辑关系,这是理解数据组织方式的基础。
A 选项:动态结构和静态结构
B 选项:紧凑结构和非紧凑结构
C 选项:线性结构和非线性结构
D 选项:内部结构和外部结构
综上,答案选 C。
若进栈序列为 1,2,3,4,进栈过程中可以出栈,则下列不可能的一个出栈顺序是( )。
A、1,4,3,2
B、2,3,4,1
C、3,1,4,2
D、3,4,2,1
栈(Stack)是一种特殊的线性数据结构,遵循 “后进先出”(Last In First Out,LIFO)的原则。就像一摞盘子,最后放上去的盘子总是最先被拿走。栈有两个主要操作:
在 C 语言中,可以使用数组或链表来实现栈。以下是一个使用数组实现栈的简单示例:
#include
#define MAX_SIZE 100
// 定义栈结构体
typedef struct {
int data[MAX_SIZE];
int top;
} Stack;
// 初始化栈
void initStack(Stack *s) {
s->top = -1;
}
// 判断栈是否为空
int isEmpty(Stack *s) {
return s->top == -1;
}
// 判断栈是否已满
int isFull(Stack *s) {
return s->top == MAX_SIZE - 1;
}
// 进栈操作
void push(Stack *s, int value) {
if (isFull(s)) {
printf("栈已满,无法进栈!\n");
return;
}
s->data[++(s->top)] = value;
}
// 出栈操作
int pop(Stack *s) {
if (isEmpty(s)) {
printf("栈为空,无法出栈!\n");
return -1;
}
return s->data[(s->top)--];
}
// 获取栈顶元素
int peek(Stack *s) {
if (isEmpty(s)) {
printf("栈为空,无栈顶元素!\n");
return -1;
}
return s->data[s->top];
}
int main() {
Stack s;
initStack(&s);
push(&s, 1);
push(&s, 2);
push(&s, 3);
printf("出栈元素: %d\n", pop(&s));
printf("栈顶元素: %d\n", peek(&s));
return 0;
}
在这个示例中:
initStack
函数用于初始化栈,将栈顶指针 top
初始化为 -1,表示栈为空。isEmpty
函数通过判断 top
是否等于 -1 来确定栈是否为空。isFull
函数通过判断 top
是否等于 MAX_SIZE - 1
来确定栈是否已满。push
函数将元素放入栈顶,先将 top
加 1,再将元素存入 data
数组中。pop
函数从栈顶移除元素,先返回 data[top]
的值,再将 top
减 1。peek
函数返回栈顶元素的值,但不改变栈的状态。在判断栈的进出序列是否可行时,需要根据栈 “后进先出” 的原则,模拟进栈和出栈的过程。具体步骤如下:
综上,答案选 C。
#include
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main() {
int num = 5;
printf("%d 的阶乘是: %d\n", num, factorial(num));
return 0;
}
在这个递归函数中,每次调用 factorial
函数时,都会将当前的 n
值和返回地址压入栈中,直到 n
等于 0 或 1 时开始返回,然后依次从栈中弹出状态,完成计算。
通过对栈的基本概念、操作和进出序列判断方法的学习,新手可以更好地理解栈这种数据结构,并能够在面试和实际编程中灵活运用。
排序方法中,将整个无序序列分割成若干子序列并分别进行插入排序的方法,称( )。
A、希尔排序
B、冒泡排序
C、插入排序
D、选择排序
d1, d2, …, dk
,其中 di > dj (i < j)
,最后一个增量 dk = 1
。k
,对序列进行 k
趟排序。di
,将待排序列分割成若干长度为 n/di
的子序列,分别对各子序列进行直接插入排序。[9, 1, 5, 8, 3, 7, 4, 6, 2]
进行希尔排序,若初始增量 d = 4
:
[9, 3], [1, 7], [5, 4], [8, 6], [2]
等子序列,分别对 [9, 3]
(排序后 [3, 9]
)、[1, 7]
(排序后 [1, 7]
)、[5, 4]
(排序后 [4, 5]
)、[8, 6]
(排序后 [6, 8]
)进行插入排序,得到新序列 [3, 1, 4, 6, 9, 7, 5, 8, 2]
。d = 2
,再对新子序列排序),直至 d = 1
时进行最后一次插入排序,最终得到有序序列。[a1, a2, …, an]
,从第一个元素开始,比较 a1
与 a2
,若 a1 > a2
则交换;再比较 a2
与 a3
,以此类推,第一趟结束后,最大元素 “沉底” 到最后位置。[5, 3, 2]
进行冒泡排序:
5
与 3
,交换得 [3, 5, 2]
;再比较 5
与 2
,交换得 [3, 2, 5]
。3
与 2
,交换得 [2, 3, 5]
,排序完成。[a1, a2, …, an]
,从第二个元素 a2
开始,将 a2
与 a1
比较,若 a2 < a1
则插入到 a1
前面;接着处理 a3
,将其与已排序的 [a1, a2]
(或 [a2, a1]
)比较,插入到合适位置,以此类推。[3, 1, 2]
进行插入排序:
3
,已排序部分 [3]
;再插入 1
,比较后得 [1, 3]
;最后插入 2
,比较 3
与 2
,交换,再比较 1
与 2
,得 [1, 2, 3]
。[a1, a2, …, an]
,第一趟从 a1
到 an
中选最小元素,与 a1
交换;第二趟从 a2
到 an
中选最小元素,与 a2
交换,以此类推。[4, 2, 5]
进行选择排序:
2
与 4
交换,得 [2, 4, 5]
;此时已基本有序(仅需再确认后续元素,本题已完成)。题目中 “将整个无序序列分割成若干子序列并分别进行插入排序”,这正是希尔排序的核心操作。冒泡排序是相邻元素比较交换,插入排序是逐个插入已排序部分,选择排序是选最值交换,均不符合题意。所以答案选 A。
通过对这些排序算法的学习,新手可深入理解不同排序方法的原理与特点,在面试和实际编程中根据需求选择合适的排序算法。
在顺序表 (3,6,8,10,12,15,16,18,21,25,30)
中,用二分法查找关键码值 11,所需的关键码比较次数为( )。
A、2
B、3
C、4
D、5
二分法查找(Binary Search),也称为折半查找,是一种高效的查找算法,但它要求被查找的序列必须是有序的(通常是升序)。其核心思想是将有序序列分成两部分,通过比较待查找的关键码值与中间元素的大小,来缩小查找范围,逐步逼近目标值,直到找到目标值或者确定目标值不存在。
假设我们有一个有序数组 arr
,要查找的关键码值为 target
,数组的起始索引为 left
,结束索引为 right
,以下是二分法查找的详细步骤:
left = 0
,right = 数组长度 - 1
。mid = (left + right) / 2
(在 C 语言中,整数除法会自动向下取整)。arr[mid] == target
,则查找成功,返回 mid
。arr[mid] > target
,说明目标值可能在左半部分,更新 right = mid - 1
,缩小查找范围到左半部分。arr[mid] < target
,说明目标值可能在右半部分,更新 left = mid + 1
,缩小查找范围到右半部分。left > right
,此时说明目标值不存在于数组中。以下是用 C 语言实现二分法查找的示例代码:
#include
// 二分法查找函数
int binarySearch(int arr[], int left, int right, int target) {
while (left <= right) {
int mid = left + (right - left) / 2; // 计算中间索引
if (arr[mid] == target) {
return mid; // 找到目标值,返回索引
} else if (arr[mid] > target) {
right = mid - 1; // 目标值在左半部分
} else {
left = mid + 1; // 目标值在右半部分
}
}
return -1; // 未找到目标值,返回 -1
}
int main() {
int arr[] = {3, 6, 8, 10, 12, 15, 16, 18, 21, 25, 30};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 11;
int result = binarySearch(arr, 0, n - 1, target);
if (result != -1) {
printf("目标值 %d 的索引是 %d\n", target, result);
} else {
printf("未找到目标值 %d\n", target);
}
return 0;
}
在这个代码中:
binarySearch
函数接受一个有序数组 arr
、起始索引 left
、结束索引 right
和目标值 target
作为参数。while
循环中,不断计算中间索引 mid
,并根据中间元素与目标值的大小关系更新查找范围。在本题中,我们要计算在顺序表 (3,6,8,10,12,15,16,18,21,25,30)
中查找关键码值 11 所需的比较次数。具体步骤如下:
left = 0
,right = 10
,计算中间索引 mid = (0 + 10) / 2 = 5
。arr[5] = 15
,因为 11 < 15
,所以目标值可能在左半部分,更新 right = mid - 1 = 4
。left = 0
,right = 4
,计算中间索引 mid = (0 + 4) / 2 = 2
。arr[2] = 8
,因为 11 > 8
,所以目标值可能在右半部分,更新 left = mid + 1 = 3
。left = 3
,right = 4
,计算中间索引 mid = (3 + 4) / 2 = 3
。arr[3] = 10
,因为 11 > 10
,所以目标值可能在右半部分,更新 left = mid + 1 = 4
。left = 4
,right = 4
,计算中间索引 mid = (4 + 4) / 2 = 4
。arr[4] = 12
,因为 11 < 12
,所以目标值可能在左半部分,更新 right = mid - 1 = 3
。此时 left > right
,查找结束,未找到目标值。综上所述,总共进行了 4 次比较,答案选 C。
通过对二分法查找的学习,新手可以掌握一种高效的查找算法,并学会如何计算查找所需的比较次数。在实际编程中,要注意二分法查找的前提条件是数据必须有序,否则可能会得到错误的结果。
( )是构成 C 语言程序的基本单位。
A、函数
B、过程
C、子程序
D、子例程
C 语言是一种函数式编程语言,其程序的基本组成单元是 函数。一个完整的 C 程序由 至少一个主函数(main
函数) 和 若干自定义函数或库函数 组成。函数是实现特定功能的代码块,具有独立的逻辑和明确的输入输出接口。
定义格式:
返回值类型 函数名(参数列表) {
// 函数体(实现具体功能的代码)
return 返回值; // 若无返回值,使用 void 类型并省略 return
}
int
、char
、void
(无返回值)等。int a, char b
)。if
、for
)等。作用:
A 选项:函数
C 语言中,程序的最小可执行单元是函数。每个程序必须有一个 main
函数作为入口,其他功能通过自定义函数或调用标准库函数(如 printf
、scanf
)实现。
// 示例:包含 main 函数和自定义函数的 C 程序
#include
// 自定义函数:计算两数之和
int add(int a, int b) {
return a + b;
}
// 主函数:程序入口
int main() {
int result = add(3, 5); // 调用自定义函数
printf("3 + 5 = %d\n", result); // 调用标准库函数
return 0;
}
B 选项:过程
“过程” 是某些编程语言(如 Pascal、Fortran)中的术语,指没有返回值的函数。但在 C 语言中,统一称为 void
类型函数,而非 “过程”。
C 选项:子程序
“子程序” 是早期编程语言(如汇编、Basic)中的概念,泛指实现特定功能的代码段。C 语言中更规范的术语是 函数,且子程序通常对应无返回值的函数,而 C 语言的函数可以有返回值或无返回值。
D 选项:子例程
“子例程” 与 “子程序” 含义相近,常见于学术或旧文档中,C 语言中标准术语是 函数。
printf
(输出,头文件 stdio.h
)、strlen
(计算字符串长度,头文件 string.h
)。add
函数。main
:特殊的用户自定义函数,是程序执行的起点,格式固定为 int main() { ... }
。int result = 函数名(参数);
void
类型):函数名(参数);
main
函数开始执行,遇到函数调用时,跳转至被调用函数的入口。题目问的是 “构成 C 语言程序的基本单位”,根据 C 语言的定义和规范,函数是程序的基本组成单元,其他选项(过程、子程序、子例程)要么是其他语言的术语,要么是 C 语言中函数的别称,而非标准术语。因此答案选 A。
int (*ptr)(int, int) = add; // 函数指针指向 add 函数
int result = ptr(3, 5); // 通过指针调用函数
printf
,需使用 stdarg.h
头文件中的宏实现。// 递归计算阶乘
int factorial(int n) {
if (n == 0) return 1;
else return n * factorial(n - 1);
}
通过理解函数在 C 语言中的核心地位,新手可以掌握模块化编程的思想,这也是嵌入式开发中编写高效、可维护代码的基础。函数的合理设计和使用,能显著提升程序的可读性和复用性,是面试中考察基础能力的重要考点。
可以在 C 语言中用作用户标识符的是( )。
A、void
B、as_b3
C、for
D、2c
用户标识符是程序员在程序中自定义的名称,用于标识变量、函数、结构体、枚举等实体。C 语言对标识符的命名有严格规则,需同时满足以下条件:
@
、#
、$
等)。 // 合法示例
int var_1; // 字母+下划线+数字
float _value; // 以下划线开头
struct student; // 纯字母
// 非法示例
int num#1; // 包含非法字符 #
char class@; // 包含非法字符 @
// 合法示例
int _start; // 以下划线开头
char abc123; // 以字母开头
// 非法示例
int 123var; // 以数字开头(错误)
float 3_sum; // 以数字开头(错误)
auto
、break
、case
、char
、const
、continue
、default
、do
、double
、else
、enum
、extern
、float
、for
、goto
、if
、int
、long
、register
、return
、short
、signed
、sizeof
、static
、struct
、switch
、typedef
、union
、unsigned
、void
、volatile
、while
等。// 非法示例(关键字不能用作用户标识符)
int int; // 错误,int 是关键字
char void; // 错误,void 是关键字
Var
和 var
是两个不同的标识符。 int var = 10; // 合法
int Var = 20; // 合法(与 var 不同)
void
void
是 C 语言的关键字,用于表示 “无类型”(如无返回值函数、无类型指针),禁止作为用户标识符。as_b3
a
开头,包含字母 s
、下划线 _
和数字 3
,符合 “字母 / 下划线开头 + 字母 / 数字 / 下划线” 的规则。int as_b3 = 5; // 合法标识符,定义整数变量
for
for
是 C 语言的关键字,用于循环语句(如 for (i=0; i<10; i++)
),禁止作为用户标识符。2c
2
开头,违反 “标识符不能以数字开头” 的规则。除了语法规则,实际编程中还需遵循以下命名规范,提高代码可读性:
见名知义:标识符应直观反映功能或用途。
// 好的命名
int student_count; // 表示学生数量
float average_score; // 表示平均分数
// 差的命名(仅语法合法,但含义模糊)
int a1; // 含义不明确
char b_2; // 难以理解用途
下划线的使用:
_var
)通常用于编译器内部或标准库,建议用户代码中避免使用,防止命名冲突。studentCount
)或下划线分隔(student_count
)。避免保留字:
_Generic
、__FILE__
等编译器内置标识符),也需避免使用。本题中唯一符合用户标识符规则的是 B 选项 as_b3
。理解标识符的命名规则是 C 语言编程的基础,也是面试中常考的细节点。新手需牢记 “字母 / 下划线开头 + 字母 / 数字 / 下划线组合 + 非关键字” 的核心规则,并在实践中养成规范命名的习惯,避免语法错误和潜在的逻辑问题。
若有以下类型说明语句:char w; int x; float y; float z;
则表达式 w * x + z - y
的结果为( )类型。
A、float
B、char
C、int
D、double
在 C 语言中,数据类型决定了数据的存储方式、取值范围以及可以进行的操作。常见的数据类型可以分为基本数据类型和派生数据类型,本题主要涉及基本数据类型中的字符型(char
)、整型(int
)和浮点型(float
)。
char
):通常占用 1 个字节的内存空间,用于存储单个字符。在计算机内部,字符以 ASCII 码的形式存储,取值范围一般是 -128 到 127 或者 0 到 255(取决于是否为有符号字符型)。int
):用于存储整数,其占用的内存空间通常为 4 个字节,取值范围根据编译器和系统的不同而有所差异。float
):用于存储单精度浮点数,占用 4 个字节的内存空间,能够表示带有小数部分的数值。在 C 语言中,当不同数据类型的操作数参与运算时,编译器会自动进行类型转换,以确保运算的正确性。类型转换主要分为两种:隐式类型转换和显式类型转换,本题主要涉及隐式类型转换。
char
和 short
类型的操作数会自动提升为 int
类型。这是因为在进行算术运算时,CPU 通常以 int
类型进行处理,这样可以提高运算效率。例如:char a = 'A';
int b = 10;
int result = a + b; // char 类型的 a 会自动提升为 int 类型
char
< short
< int
< long
< float
< double
。例如,当 int
类型和 float
类型的操作数进行运算时,int
类型会自动转换为 float
类型。对于表达式 w * x + z - y
,按照运算符的优先级,先计算 w * x
,再将结果与 z
相加,最后减去 y
。下面详细分析每一步的运算过程:
w * x
w
是 char
类型,x
是 int
类型,根据整型提升规则,w
会自动提升为 int
类型。int
类型的操作数相乘,结果仍然是 int
类型。例如:char w = 'A'; // ASCII 码值为 65
int x = 10;
int temp = w * x; // 结果为 650,类型为 int
temp + z
temp
是 int
类型,z
是 float
类型。根据类型转换的优先级,int
类型的 temp
会自动转换为 float
类型。float
类型的操作数相加,结果为 float
类型。例如:float z = 3.14;
float sum = temp + z; // temp 转换为 float 类型后相加,结果为 653.14,类型为 float
sum - y
sum
是 float
类型,y
也是 float
类型。两个 float
类型的操作数相减,结果仍然是 float
类型。例如:float y = 1.23;
float final_result = sum - y; // 结果为 651.91,类型为 float
根据上述对表达式 w * x + z - y
运算过程的分析,最终结果的类型为 float
类型。所以答案选 A。
(目标类型)表达式
。例如:int a = 10;
float b = (float)a; // 将 int 类型的 a 强制转换为 float 类型
需要注意的是,显式类型转换可能会导致数据精度的丢失,例如将 float
类型转换为 int
类型时,小数部分会被截断。
double
类型:double
类型是双精度浮点数类型,占用 8 个字节的内存空间,比 float
类型具有更高的精度和更大的取值范围。在某些情况下,如果表达式中包含 double
类型的操作数,其他类型的操作数会自动转换为 double
类型进行运算。例如:int a = 10;
double b = 3.14;
double result = a + b; // int 类型的 a 会自动转换为 double 类型
通过对本题的学习,新手可以深入理解 C 语言中类型转换的规则,以及如何根据表达式中操作数的类型来判断最终结果的类型。这对于编写正确的代码和避免潜在的错误非常重要。
main() {
int a=0, b=0, c=0;
if(++a>0||++b>0)++c;
printf("\na=%d, b=%d, c=%d", a, b, c);
}
A、a=0, b=0, c=0
B、a=1, b=1, c=1
C、a=1, b=0, c=1
D、a=0, b=1, c=1
在 C 语言中,变量必须先定义后使用。定义变量时需要指定变量的类型,如 int
(整型)、float
(浮点型)等。同时,可以在定义变量的同时对其进行初始化,即赋予初始值。
int a = 0; // 定义一个整型变量 a,并初始化为 0
float b = 3.14; // 定义一个浮点型变量 b,并初始化为 3.14
在本题中,int a=0, b=0, c=0;
定义了三个整型变量 a
、b
和 c
,并将它们都初始化为 0。
++
)自增运算符 ++
用于将变量的值加 1。它有两种使用方式:前缀自增和后缀自增。
++变量
):先将变量的值加 1,然后再使用变量的值。int x = 5;
int y = ++x; // 先将 x 的值加 1 变为 6,然后将 6 赋值给 y
变量++
):先使用变量的值,然后再将变量的值加 1。int x = 5;
int y = x++; // 先将 x 的值 5 赋值给 y,然后 x 的值加 1 变为 6
在本题中,++a
和 ++b
都是前缀自增,会先将 a
和 b
的值加 1,然后再使用它们的值进行后续的比较操作。
||
)逻辑或运算符 ||
用于对两个表达式进行逻辑或运算。它的运算规则是:只要两个表达式中有一个为真(非 0),整个逻辑或表达式就为真;只有当两个表达式都为假(0)时,整个逻辑或表达式才为假。
逻辑或运算符具有短路特性,即当左边的表达式为真时,右边的表达式将不再进行计算。这是因为只要左边的表达式为真,整个逻辑或表达式就已经确定为真,不需要再计算右边的表达式。
int m = 1;
int n = 2;
if (m > 0 || n > 3) {
// 由于 m > 0 为真,根据短路特性,n > 3 不会被计算
printf("条件为真\n");
}
if
语句if
语句用于根据条件的真假来决定是否执行特定的代码块。其基本语法如下:
if (条件表达式) {
// 当条件表达式为真时执行的代码块
}
如果条件表达式的值为真(非 0),则执行 if
语句后面的代码块;如果条件表达式的值为假(0),则跳过该代码块。
printf
函数printf
函数是 C 语言标准库中的一个输出函数,用于将格式化的字符串输出到标准输出设备(通常是屏幕)。其基本语法如下:
printf("格式化字符串", 参数列表);
%
开头,用于指定参数的输出格式,如 %d
用于输出整数,%f
用于输出浮点数等。int num = 10;
printf("num 的值是: %d\n", num); // 输出 num 的值
下面详细分析本题中代码的执行过程:
int a=0, b=0, c=0;
定义了三个整型变量 a
、b
和 c
,并将它们都初始化为 0。
2. 逻辑或表达式的计算:
if(++a>0||++b>0)++c;
++a
,由于是前缀自增,a
的值先加 1 变为 1。然后判断 ++a > 0
,即 1 > 0
,该表达式为真。||
具有短路特性,当左边的表达式 ++a > 0
为真时,右边的表达式 ++b > 0
将不再进行计算。因此,b
的值仍然为 0。if
语句的执行:++a > 0 || ++b > 0
的值为真,所以会执行 ++c
。c
的值先加 1 变为 1。printf("\na=%d, b=%d, c=%d", a, b, c);
使用 printf
函数输出 a
、b
和 c
的值,即 a=1, b=0, c=1
。
综上所述,答案选 C。
&&
):逻辑与运算符 &&
用于对两个表达式进行逻辑与运算。它的运算规则是:只有当两个表达式都为真时,整个逻辑与表达式才为真;只要有一个表达式为假,整个逻辑与表达式就为假。逻辑与运算符也具有短路特性,即当左边的表达式为假时,右边的表达式将不再进行计算。int p = 0;
int q = 2;
if (p > 0 && q > 3) {
// 由于 p > 0 为假,根据短路特性,q > 3 不会被计算
printf("条件为真\n");
}
if
语句:if
语句可以嵌套使用,即在一个 if
语句的代码块中再使用另一个 if
语句。嵌套 if
语句可以实现更复杂的条件判断。int x = 10;
int y = 20;
if (x > 5) {
if (y > 15) {
printf("x 大于 5 且 y 大于 15\n");
}
}
通过对本题的学习,新手可以深入理解 C 语言中变量的初始化、自增运算符、逻辑运算符的短路特性、if
语句和 printf
函数的使用,这些都是 C 语言编程的基础知识点,在面试和实际编程中都非常重要。
#define A 100
main() {
int i=0, sum=0;
do {
if(i%2==0) continue;
sum += i;
} while(i++ < A);
printf("%d", sum);
}
分析代码输出结果,并解释涉及的知识点。
#define
)A
替换为 100
)。#define 宏名 替换文本
(无分号结尾,纯文本替换)。#define PI 3.14159 // 定义宏 PI 为圆周率
float circle_area = PI * r * r; // 编译时 PI 会被替换为 3.14159
#define A 100
将 A
替换为 100
,循环条件 i++ < A
实际为 i++ < 100
。do-while
循环do {
// 循环体代码
} while (条件表达式); // 注意分号结尾
while
循环的区别:while
先判断条件,可能一次都不执行循环体;do-while
至少执行一次。continue
语句for (int i=0; i<5; i++) {
if (i==2) continue; // 跳过 i=2 时的循环体后续代码
printf("%d ", i); // 输出 0 1 3 4
}
i%2==0
(i
为偶数)时,执行 continue
,跳过 sum += i
,直接进入 while
条件判断。%
)被除数 % 除数
(除数不能为 0)。int a=7, b=3;
printf("%d", a%b); // 输出 1(7 ÷ 3 余 1)
i%2==0
用于判断 i
是否为偶数(余数为 0 则是偶数)。i++
)i
的当前值进行运算,再将 i
的值加 1。++i
)的区别:
i++
:先用值,再加 1(如 a = i++
等价于 a = i; i = i+1;
)。++i
:先加 1,再用值(如 a = ++i
等价于 i = i+1; a = i;
)。while(i++ < A)
中,先判断 i < 100
,再将 i
自增 1。int i=0, sum=0;
:i
为循环变量(从 0 开始),sum
用于累加奇数。第一次循环(i=0):
do
进入循环体,执行 if(i%2==0)
:0%2=0
,条件成立,执行 continue
,跳过 sum += i
,直接进入 while(i++ < A)
。i=0 < 100
为真,执行 i++
,i
变为 1。第二次循环(i=1):
i%2=1%2=1≠0
,不执行 continue
,执行 sum += i
(sum=0+1=1
)。i=1 < 100
为真,执行 i++
,i
变为 2。第三次循环(i=2):
i%2=0
,执行 continue
,跳过累加,条件判断 i=2 < 100
为真,i++
变为 3。后续循环(i=3 到 i=99):
i
为奇数时(i%2≠0
),累加 i
到 sum
;当 i
为偶数时,跳过累加。i++
,直到 i=99
时:
99
到 sum
,i++
变为 100。i=100 < 100
为假,循环结束。i
的最终值为 100(因最后一次判断时 i=99
,条件成立,i++
后为 100)。sum
累加的是所有 1 到 99 之间的奇数。sum
最终值为 2500。#define A 100 // 宏定义,编译时 A 替换为 100
main() {
int i=0, sum=0; // 初始化循环变量 i 和累加器 sum
do {
if(i%2==0) continue; // 如果 i 是偶数,跳过本次循环的累加操作
sum += i; // 否则(i 是奇数),将 i 累加到 sum
} while(i++ < A); // 先判断 i < 100,再自增 i(后自增)
printf("%d", sum); // 输出累加结果 2500
}
continue
vs break
continue
:跳过本次循环,进入下一次循环(不终止循环)。break
:终止整个循环,跳出循环体。// 示例:break 终止循环
for (int i=0; i<5; i++) {
if (i==2) break; // 当 i=2 时,跳出循环,不再执行后续迭代
printf("%d ", i); // 输出 0 1
}
a = i++ + ++i
(行为未定义,不同编译器可能有不同结果)。i%2==1
,还可利用位运算 i&1
(奇数时结果为 1,偶数为 0),效率更高: if (i & 1) sum += i; // 等价于 if (i%2==1)
本题综合考察了 do-while
循环、continue
语句、宏定义、取模运算和后自增运算符。关键在于理解:
do-while
循环 “先执行后判断” 的特性。continue
对循环体的跳过逻辑。i++
在条件判断中的执行顺序。通过逐步分析循环迭代过程,并结合数学推导,最终得出输出结果为 2500。这些知识点是嵌入式开发中编写高效循环代码的基础,也是面试中考察逻辑思维和细节处理能力的重点。
通过对这些经典试题的详细解析,希望能帮助大家深入理解 C 语言基础,在嵌入式面试中脱颖而出。后续将继续分享更多嵌入式开发相关知识,敬请关注!