If-Else
语法
if (expression)
statement1
else
statement2
Else-If
语法
if (expression1) {
// 条件expression1为真时执行的语句
} else if (expression2) {
// 条件expression1为假,且expression2为真时执行的语句
} else if (expression3) {
// 条件expression1和expression2为假,且expression3为真时执行的语句
// 可以有更多else if分支
} else {
// 所有条件expression1, expression2, expression3等都为假时执行的语句
}
举例
二分法查找。(注意:数组必须有序)
#include <stdio.h> // 引入标准输入输出库,用于printf函数
// 函数声明:在已排序的数组v中使用二分查找算法查找元素x
int binsearch(int x, int v[], int n);
int main() {
int v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // 定义一个已排序的数组v
// 调用binsearch函数,查找元素7在数组v中的位置,并打印返回的索引
printf("%d\n", binsearch(7, v, 9));
}
// 函数定义:在已排序的数组v中使用二分查找算法查找元素x
int binsearch(int x, int v[], int n) {
int mid, low, high; // 定义中间索引mid,以及搜索范围的low和high
low = 0; // 初始化low为0,指向数组的开始
high = n - 1; // 初始化high为n-1,指向数组的末尾
// 循环进行二分查找,直到low大于high
while (low <= high) {
mid = (low + high) / 2; // 计算中间索引mid
// 根据x与数组中间元素v[mid]的比较结果更新搜索范围
if (x < v[mid])
high = mid - 1; // 如果x小于v[mid],则更新high为mid-1
else if (x > v[mid])
low = mid + 1; // 如果x大于v[mid],则更新low为mid+1
else
return mid; // 如果找到x,则返回索引mid
}
// 如果未找到x,则返回-1
return -1;
}
练习
- 我们的二分查找在循环内进行了两次测试,但一次测试就足够了(代价是需要进行更多的外部测试)。编写一个循环内只进行一次测试的版本,并测量运行时间的差异。
#include <stdio.h> // 引入标准输入输出库
#include <time.h> // 引入时间处理库
// 函数声明:二分查找算法
int binsearch(int x, int v[], int n);
int main() {
int v[1000]; // 定义一个大小为1000的整型数组
// 初始化数组v,将每个元素设置为其索引值
for (int i = 0; i < 1000; i++)
v[i] = i;
clock_t start, end; // 定义开始和结束时间变量
double cpu_time_used; // 定义用于存储CPU时间的变量
start = clock(); // 记录二分查找开始时间
// 在循环中重复调用binsearch函数1000000次
for (int i = 0; i < 1000000; i++)
binsearch(73, v, 10);
end = clock(); // 记录二分查找结束时间
// 计算经过的CPU时间,并转换为秒
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
// 打印经过的时间
printf("Time used: %f seconds\n", cpu_time_used);
}
// 二分查找算法实现
int binsearch(int x, int v[], int n) {
int mid, low, high;
low = 0; // 初始化low为0
high = n - 1; // 初始化high为数组末尾索引
// 循环进行二分查找,直到low大于high
while (low <= high) {
mid = low + (high - low) / 2; // 计算中间索引,防止溢出
// 进行查找,根据比较结果更新搜索范围
if (x < v[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
// 如果未找到x,返回-1
return -1;
}
Switch
语法
switch (expression) {
case constant_expression1:
// 代码块1
break;
case constant_expression2:
// 代码块2
break;
...
default:
// 默认代码块,可选
}
注意:
- switch语句开始于圆括号内的表达式(expression),这个表达式的结果通常是一个整数或枚举类型。
举例
#include <stdio.h>
int main() {
int month;
printf("Enter a month (1-12): ");
scanf("%d", &month);
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
printf("%d is a month with 31 days.\n", month);
break;
case 4:
case 6:
case 9:
case 11:
printf("%d is a month with 30 days.\n", month);
break;
case 2:
printf("%d is February.\n", month);
// 没有break,将继续执行下一个case的代码
default:
printf("Invalid month.\n");
}
return 0;
}
Loops - While, For and Do-While
- For循环
- 语法
for (初始化表达式; 条件表达式; 递增/递减表达式) {
// 循环体
}
- 举例
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
- While循环
- 语法
while (条件表达式) {
// 循环体
}
- 举例
int i = 0;
while (i < 10) {
printf("%d ", i);
i++;
}
- Do-While循环
- 语法
do {
// 循环体
} while (条件表达式);
- 举例
int i = 0;
do {
printf("%d ", i);
i++;
} while (i < 10);
举例
将整数转换为字符串。
void atoi(int n, char s[]) {
int i, sign;
// 检查整数n是否为负数,并保存符号
if ((sign = n) < 0) // 此处存在逻辑错误,应使用'='进行赋值,而非比较
n = -n;
i = 0; // 初始化字符串索引
do {
// 将数字n的最低位加到字符串s的末尾,并递增索引i
s[i++] = n % 10 + '0';
} while ((n /= 10) > 0); // 循环直到n变为0
// 缺少reverse函数的定义,该函数应该用于反转字符串s
reverse(s);
}
练习
- 关于
atoi
函数有一个漏洞,当n=-2,147,483,648
时,n = -n
会溢出。请修改atoi
,使其不会出现溢出问题。
void atoi(int n, char s[]) {
int i, sign;
// 判断 n 的符号并存储
if ((sign = n) < 0) // 如果 n 是负数
; // sign 被赋值为负数
i = 0;
do {
// 取 n 的个位数转换为字符并存储到 s 中
// 如果 n 是正数,直接取余数
// 如果 n 是负数,先取余数再取负值
s[i++] = (sign > 0) ? (n % 10 + '0') : (-1 * (n % 10) + '0');
} while ((n /= 10) != 0); // 将 n 除以 10 并更新 n,直到 n 变为 0
if (sign < 0)
s[i++] = '-'; // 如果 n 是负数,添加负号到 s 中
s[i] = '\0'; // 在字符串末尾添加结束符 '\0'
reverse(s); // 反转字符串 s
}
- 编写一个函数
itob(int n, char s[], int b)
,将整数n
转为b
进制的字符串。
#include <stdio.h>
#include <string.h>
void itob(int n, char s[], int b);
void reverse(char s[]);
int main() {
char str[12]; // 声明一个大小为 12 的字符数组,用于存储转换后的字符串
itob(-235, str, 16); // 将 -235 转换为十六进制并存储在 str 中
printf("%s\n", str); // 打印转换后的字符串
return 0;
}
// 反转字符串 s 的函数
void reverse(char s[]) {
int i, j;
char temp;
// 使用双指针法进行字符串反转
for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
// 将整数 n 转换为指定进制 b 的字符串表示存储在 s 中的函数
void itob(int n, char s[], int b) {
int i, sign, c;
if ((sign = n) < 0)
; // 如果 n 是负数,sign 被赋值为负数,但此处没有实际操作
i = 0;
do {
// 取 n 对 b 取模的结果,转换为对应的字符并存储到 s 中
// 如果 n 是正数,直接取余数
// 如果 n 是负数,先取余数再取负值
c = (sign > 0) ? (n % b + '0') : (-1 * (n % b) + '0');
if (c > '9')
s[i++] = c - '9' - 1 + 'a'; // 如果超过 9,转换为 a-f 的字母形式
else
s[i++] = c;
} while ((n /= b) != 0); // 将 n 除以 b 并更新 n,直到 n 变为 0
if (sign < 0)
s[i++] = '-'; // 如果 n 是负数,添加负号到 s 中
s[i] = '\0'; // 在字符串末尾添加结束符 '\0'
reverse(s); // 反转字符串 s,使得最终结果正确表示 n 的 b 进制数
}
Break and Continue
Break
- break 用于立即终止包含它的最内层循环的执行。
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // 当i等于5时,退出循环
}
printf("%d ", i);
}
// 输出: 0 1 2 3 4
Continue
- continue 用于跳过当前循环迭代的剩余部分,并立即进入下一次迭代。
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数,不执行下面的打印语句
}
printf("%d ", i);
}
// 输出: 1 3 5 7 9