楼主: 凫雁满回糖
292 0

[作业] C语言小知识——第二期 [推广有奖]

  • 0关注
  • 0粉丝

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
9 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-10-8
最后登录
2018-10-8

楼主
凫雁满回糖 发表于 2025-12-9 07:02:44 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

占位符、运算符、循环结构以及switch语句构成了C语言中输入输出与流程控制的核心内容。熟练掌握这些基础知识,有助于构建清晰的程序逻辑,为后续深入学习编程打下坚实基础。

一、占位符的使用

在C语言中,scanf()printf() 函数广泛使用占位符来处理不同类型的输入输出数据。两者所用占位符基本相同,但存在细微差别。

1. 常见占位符列表

  • %c:用于读取或输出单个字符。
  • %d:处理有符号整型数据。
  • %f:对应 float 类型的浮点数。
  • %lf:用于 double 类型浮点数的输入输出。
  • %Lf:适用于 long double 类型。
  • %s:读取或打印字符串(以空格、换行等空白字符结束)。
  • %[]:指定一组可匹配的字符集合(如 %[0-9]),当遇到不在集合中的字符时停止读取。
char name[11]; // 数组长度为11(包含末尾的\0)
scanf("%10s", name); // %10s表示最多读10个字符,加上\0刚好不溢出

2. %s 的读取特性与注意事项

  1. 起始规则:%s 自动跳过开头的空白字符,从第一个非空白字符开始读取。
  2. 终止条件:一旦遇到空格、制表符或换行符即停止,因此无法完整读取包含空格的字符串(例如 "Hello World" 只能获取到 "Hello")。
  3. 自动添加结束符:系统会在读入的字符串末尾自动追加 '\0' 作为结束标记。
  4. 数组溢出风险scanf("%s", arr) 不会检查输入长度是否超出数组容量,容易引发缓冲区溢出问题。

解决方案:限制最大读取长度

可通过 %ms 格式(m为整数)限定最多读取 m 个字符,避免越界。例如:

char arr[11]; scanf("%10s", arr);

此处数组大小应比允许读取的最大字符数多1,以便容纳结尾的 \0 字符。

核心结论:使用 scanf 读取字符串时务必加上长度限制(如 %10s),防止内存越界错误。

char arr[20];
scanf("%[0-9]", arr);
printf("%s\n", arr);
//输入123abc456
//输出123
//原理:%[0-9]表示仅匹配0-9的数字字符,遇到非数字字符(此处为a)时立即停止读取,因此只截取了123存入数组。
char arr[20];
scanf("%s", arr);
printf("%s\n", arr);
//输入abc def
//输出abc
//原理:%s是scanf读取字符串的默认方式,遇到空格、制表符或换行符时停止读取,因此只截取了空格前的abc。
char arr[20];
scanf("%[^\n]", arr);
printf("%s\n", arr);
//输入abc def
//输出abc def
//原理:%[^\n]表示匹配除换行符\n之外的所有字符,会读取到用户按下回车键为止,因此能完整读取包含空格的整行内容。

3. printf 与 scanf 在浮点类型上的差异

函数 float 类型 double 类型
printf 可用 %f 输出 可用 %f 或 %lf 输出
scanf 必须用 %f 输入 必须用 %lf 输入

二、赋值忽略符(*)的应用

1. 概念说明

scanf 中,格式字符串里使用 %*格式符(如 %*d、%*c)表示“解析但不赋值”,即跳过该部分输入内容,不将其存入任何变量。

2. 典型应用场景

适用于输入中包含固定分隔符或无关信息的情况:

  • 日期格式中的 '-' 或 '/' 分隔符无需保存。
  • 某些数值序列中只需提取特定位置的数据。

3. 使用示例

示例一:灵活读取日期(支持 - 或 / 分隔)

scanf("%d%*c%d%*c%d", &year, &month, &day);

输入 2024-10-05 或 2024/10/05 均可正确解析为 year=2024, month=10, day=5。

int year, month, day;
// %*c 表示解析1个字符(分隔符),但不赋值
scanf("%d%*c%d%*c%d", &year, &month, &day);
printf("年:%d,月:%d,日:%d\n", year, month, day);

示例二:忽略中间数值

若输入为 "10 20 30",仅需获取首尾两个数:

scanf("%d%*d%d", &a, &c);

结果 a=10, c=30,中间的 20 被自动跳过。

int a, c;
scanf("%d%*d%d", &a, &c); // %*d 忽略中间的20
printf("%d %d\n", a, c); // 输出10 30

4. 注意事项

  • 星号 * 必须紧接在 % 后、格式符前,如 %*c、%*s 等均合法。
  • 被忽略的内容仍需符合指定格式,否则会导致整个 scanf 解析失败并提前终止。

三、关系操作符详解

1. 基本定义

关系操作符用于比较两个操作数之间的大小或相等性,构成的关系表达式返回整型值:1 表示真,0 表示假。

2. 六种关系运算符及其行为

  • >(大于)
    示例:a=3, b=5 → a > b 结果为 0(假)
  • <(小于)
    示例:a=3, b=5 → a < b 结果为 1(真)
  • >=(大于等于)
    示例:b=5, a=3 → b >= a 结果为 1(真)
  • <=(小于等于)
    示例:a=3, b=5 → a <= b 结果为 1(真)
  • ==(等于)
    示例:a=3, b=5 → a == b 结果为 0(假)
  • !=(不等于)
    示例:a=3, b=5 → a != b 结果为 1(真)

3. 关键提醒

  1. 区分 = 与 ==
    = 是赋值操作符,而 == 才是判断相等的操作符。常见错误写法 if (x = 5) 实际上是赋值而非比较,应改为 if (x == 5)
  2. 禁止连续书写关系符
    类似 i < j < k 的表达式在C中是逻辑错误。C会先计算 i < j 得到 0 或 1,再将结果与 k 比较。正确方式应使用逻辑与连接:i < j && j < k

四、条件操作符(三目操作符)

1. 概述

条件操作符又称三目操作符,是C语言中唯一需要三个操作数的运算符。相较之下,双目操作符需两个操作数,单目操作符仅需一个。

2. 语法结构

其标准形式如下:

exp1 ? exp2 : exp3

其中:

  • exp1:条件判断表达式,决定后续执行路径。
  • ?:条件操作符的关键分隔符。
  • exp2:当 exp1 为真(非零)时执行或计算的部分。
  • ::分支结果的分隔符号。
  • exp3:当 exp1 为假(零)时执行或计算的部分。

3. 执行逻辑

首先评估 exp1 的真假性。若其结果为真(即非0值),则计算 exp2,并将 exp2 的值作为整个三目表达式的结果;反之,则计算 exp3 并以其结果作为整体返回值。

当 exp1 的结果为假(在C语言中用0表示)时,系统会转而计算 exp3,此时 exp3 的值就成为整个条件表达式的最终结果。

4. 示例解析

以判断一个数值是否为正数为例:

int num = 5;
int result = (num > 0) ? 1 : 0;
// exp1是num>0(结果为真),所以计算exp2的1,result最终为1

总结: 条件操作符采用 exp1 ? exp2 : exp3 的形式,属于三目运算符。根据 exp1 的真假情况来决定是计算 exp2 还是 exp3,并将该计算结果作为整体表达式的返回值。

五、逻辑操作符
1. 基本概念

逻辑运算符用于实现逻辑判断,能够组合多个条件形成更复杂的表达式。在C语言中,主要包含以下三种逻辑运算符:!、&&、||。

注意:在C语言中,所有非0值被视为“真”,而0则代表“假”。

2. 各运算符说明

(1)!:逻辑取反运算符(单目运算符,仅需一个操作数)
作用:对单一表达式的逻辑值进行反转。

示例:
!10 → 由于10为非0(即“真”),取反后结果为假,即0
!0 → 因为0表示“假”,取反后变为“真”,结果为1

(2)&&:逻辑与运算符(双目运算符,需要两个操作数)
作用:表示“并且”的关系。

规则:只有当两侧的表达式都为真时,整个表达式才为真;只要有一个为假,则整体为假。

示例:
(3>2) && (5<10) → 两边均为真,因此结果为1(真)
(3>2) && (5>10) → 右侧为假,整体结果为0(假)

(3)||:逻辑或运算符(双目运算符,需要两个操作数)
作用:表示“或者”的含义。

规则:只要其中一个表达式为真,整个表达式即为真;仅当两个都为假时,结果才为假。

示例:
(3>2) || (5>10) → 左侧为真,故结果为1(真)
(3<2) || (5>10) → 两侧皆为假,结果为0(假)

3. 短路特性

(1)短路的前提
在C语言中,对于逻辑运算符 && 和 ||,总是先计算左侧表达式的值,再考虑右侧,这一执行顺序是固定的。

(2)短路的定义
如果左侧表达式的值已经足以确定整个逻辑表达式的结果,则不会继续计算右侧表达式,这种现象称为“短路”。

(3)两种短路情形

逻辑与(&&)的短路:
规则:当左侧表达式为假时,无论右侧为何值,整个 && 表达式必定为假,因此不再计算右侧部分。

示例:

(0 > 1) && (5 / 0); // 左侧0>1是假,右侧5/0不会执行,避免报错

逻辑或(||)的短路:
规则:若左侧表达式为真,则整个 || 表达式已确定为真,无需再评估右侧表达式。

示例:

(2 > 1) || (5 / 0); // 左侧2>1是真,右侧5/0不会执行,避免报错
六、switch语句
1. 基本功能

switch语句是一种特殊的多分支选择结构,适用于存在多种可能匹配条件的情况。相比多重嵌套的 else if 结构,它具有更高的可读性和更清晰的代码组织方式。

2. 语法格式
switch (expression)
{
    case value1:
        语句块1;
        break;
    case value2:
        语句块2;
        break;
    ...
    default:
        语句块n;
        break;
}
3. 执行流程

程序会根据表达式 expression 的实际值,查找与其相等的 case 分支并执行对应代码块;若没有任何 case 匹配成功,则执行 default 分支中的内容。

4. 使用注意事项
  • switch 后面的 expression 必须是整型表达式,如 int、char 等类型均可,但不能使用浮点型或字符串。
  • 每个 case 后面的值必须是整型常量表达式,例如直接写数字或字符常量,不允许使用变量。
  • case 关键字与后续数值之间必须保留至少一个空格。
    正确写法:case 1:
    错误写法:case1: 或 case ?1:(含非法字符或缺少空格)
  • 每个 case 分支结束后建议添加 break 语句以跳出 switch 结构。
    若省略 break,将引发“贯穿”现象——当前 case 执行完毕后,程序将继续执行其后的所有 case 和 default 分支,直到遇到 break 或到达 switch 末尾。

示例:

int num = 1;
switch (num) {
    case 1:
        printf("A");
        // 没有break
    case 2:
        printf("B");
        break;
    default:
        printf("C");
}
// 执行结果是AB(因为case1没有break,会继续执行case2)
5. case 与 default 的排列顺序

(1)核心规则
在 switch 语句中,case 和 default 子句的出现顺序没有语法上的强制要求。只要符合逻辑需求,可以任意排列,编译器均能接受。

(2)编程习惯
尽管语法允许自由排序,但在实际开发中,通常将 default 放置在所有 case 之后。
原因在于:default 是“无匹配项时执行”的兜底分支,将其置于最后更符合人类阅读习惯,有助于提升代码的清晰度和维护性。

(3)示例说明
即使将 default 写在 case 之前,程序依然可以正常运行:

int num = 5;
switch (num) {
    default:
        printf("无匹配值");
        break;
    case 1:
        printf("数字1");
        break;
    case 2:
        printf("数字2");
        break;
}
// 执行结果:无匹配值
七、循环语句与 break/continue
(一)三种循环结构

C语言提供了 while、for 和 do-while 三种循环语句,它们均基于条件控制重复执行某段代码,但在执行机制上有所区别。

1. while 循环

语法结构:

while(表达式)
    语句; // 循环体,多语句需加{}

执行逻辑: 首先判断条件表达式,若结果为真(非0),则执行循环体;若为假(0),则跳过循环体,结束循环。

特点: 循环体有可能一次都不被执行(初始条件即为假时)。

关键细节(常见陷阱):

  • 循环条件中必须包含能够使循环终止的逻辑,否则可能导致死循环。例如 while(1) 永远为真,必须配合 break 才能退出。
  • 循环变量的更新操作应放在循环体内,遗漏会导致条件始终成立,从而陷入无限循环。例如,在求 1 到 10 的累加时,忘记写 i++ 将导致循环无法终止。
  • while 后的表达式后不应加分号。误写成 while(1); 会使循环体成为空语句,导致后续代码脱离循环控制。
2. for 循环

语法结构:

for(表达式1; 表达式2; 表达式3)
    语句; // 循环体,多语句需加{}

表达式1: 用于初始化循环变量,仅在循环开始前执行一次。

3. do-while循环

语法结构:

do
    语句; // 循环体,多语句需加{}
while(表达式);

执行逻辑:程序进入循环后,会首先执行一次循环体(无论循环条件是否成立,都会至少执行一次);随后判断「循环条件表达式」:若结果非0,则返回继续执行下一轮循环体;若结果为0,则跳出循环,转而执行循环之后的代码。

关键细节(避坑重点):

  • do-while语句末尾必须带有分号,这是语法强制要求,遗漏将导致编译错误——此为最常见错误之一;
  • 循环变量的初始化需在do语句之前手动完成,变量调整操作可置于循环体内;
  • 由于循环体必定执行一次,因此不适合用于“可能无需执行”的场景。例如在查询数据时,若无数据则不应处理,此时使用while更为合适;
  • 特点:保证循环体至少运行一次,是三种循环结构中使用频率最低的一种。

(二)break与continue语句

这两个关键字用于控制循环流程,其作用范围仅限于当前所处的第一层循环。

1. break语句(终止循环或跳出分支)

(1)核心作用

  • 当应用于循环时:立即永久终止当前所在的第一层循环,跳转至循环体外后续代码,不再继续执行该循环;
  • 当应用于switch语句时:结束当前switch结构,防止case穿透现象发生(注意:此处的break与循环无关,仅为分支控制用途)。

(2)执行逻辑(在循环中的表现)

  1. 循环正常进行过程中,一旦满足break触发条件并执行break;
  2. 系统立刻中断当前循环,跳过循环体内剩余所有代码;
  3. 程序流程直接跳转至循环结束后的第一条语句继续执行。

(3)关键细节

  • 仅对「当前第一层循环」生效,在嵌套循环中,内层break不会影响外层循环的执行;
  • 通常与条件判断(如if语句)结合使用,实现“满足特定条件即提前退出循环”的逻辑(例如:查找目标值成功后立即停止遍历);
  • 可用于手动控制死循环的退出机制(例如:while(1) 配合 if(条件) break 实现可控终止)。

(4)典型示例:寻找100以内第一个能被17整除的数,找到后立即停止搜索。

#include <stdio.h>
int main() {
    int num;
    for (num = 1; num <= 100; num++) {
        if (num % 17 == 0) {
            printf("100以内第一个能被17整除的数:%d\n", num); // 输出17
            break; // 找到后终止循环,无需继续遍历
        }
    }
    return 0;
}

2. continue语句

(1)核心作用

  • 仅适用于循环结构:跳过当前这一次循环体中剩余的所有代码,不终止整个循环,而是直接进入下一次循环的准备阶段(包括条件判断或变量调整)。

(2)不同循环中的执行差异(核心避坑点)

while循环中:

  • 执行continue后,程序跳过循环体后续代码,直接回到「循环条件表达式的判断」环节;
  • 如果循环变量的更新语句位于continue之后,则无法被执行,可能导致条件始终为真,从而引发死循环(高频陷阱)。

示例:计算1到10之间所有奇数的和(错误写法 vs 正确写法)

// 错误示例(死循环):i++在continue后,跳过调整,i永远=1
int i=1, sum=0;
while(i<=10){
    if(i%2==0) continue; // 偶数时跳过
    sum += i;
    i++; // 永远执行不到,死循环
}

// 正确示例:i++在continue前,确保每次循环都调整变量
int i=1, sum=0;
while(i<=10){
    if(i%2==0){
        i++;
        continue; // 偶数时先调整i,再跳过求和
    }
    sum += i;
    i++;
}

for循环中:

  • 执行continue后,跳过当前循环体剩余部分,直接进入「循环变量调整表达式(即表达式3)」;
  • 随后再进行条件判断。由于变量调整在continue之后仍会被自动执行,因此不会造成死循环——这是使用continue最安全的场景。

示例:计算1到10之间所有奇数的和(正确写法)

int sum=0;
for(int i=1;i<=10;i++){
    if(i%2==0) continue; // 偶数跳过求和,直接执行i++
    sum += i;
}
printf("1-10奇数和:%d\n", sum); // 输出25

do-while循环中:

  • 执行逻辑与while完全相同:continue后跳过剩余代码,直接回到「循环条件表达式判断」;
  • 若循环变量的调整操作写在continue之后,同样会导致变量无法更新,从而陷入死循环,因此必须确保变量调整在continue前完成。

关键细节总结:

  • 仅跳过「本次循环」中尚未执行的代码,循环本身不会终止,下一轮循环将正常启动;
  • 在嵌套循环中,仅影响当前所在的那一层循环,对外层或其他内层无影响;
  • 不能单独使用,必须配合条件判断(如if),否则会造成每次循环都无意义地跳过剩余内容。
语句 核心作用 循环后续状态 适用场景
break 终止当前第一层循环 循环永久结束 满足条件时提前退出循环
continue 跳过本次循环剩余代码 进入下一次循环 满足条件时不执行本次的部分逻辑

(三)循环进阶用法(嵌套循环、死循环、循环优化)

(1)嵌套循环(循环内部包含另一个循环,外层控制轮数,内层处理细节)

核心规则:

  • 外层每执行一次,内层就会完整运行一轮(从初始状态到条件为假为止);
  • 内外层循环变量应使用不同名称以避免冲突(推荐:外层用i,内层用j等);
  • break和continue仅作用于当前所在的循环层级,内层的操作不会干扰外层循环。

典型示例:打印九九乘法表

#include <stdio.h>
int main() {
    // 外层循环:控制行数(1-9行)
    for (int i = 1; i <= 9; i++) {
        // 内层循环:控制每行列数(1-i列,与行数匹配)
        for (int j = 1; j <= i; j++) {
            printf("%d×%d=%d\t", j, i, j*i);
        }
        printf("\n"); // 每行结束换行
    }
    return 0;
}

(2)死循环(无限重复执行的循环,需通过外部条件手动终止)

常见写法(共3种):

// 写法1:while(1)(最常用,可读性强)
while (1) {
    if (条件) break; // 必须加break,否则无法终止
    ...
}

// 写法2:for(;;)(语法合法,三表达式省略)
for (;;) {
    if (条件) break;
    ...
}

// 写法3:do-while(1)(循环体必执行1次)
do {
    if (条件) break;
    ...
} while (1);

(四)高频易错点汇总(避坑清单)

  1. 循环条件缺少有效的终止机制,导致死循环(例如:while(i<=10)但忘记写i++);
  2. for循环中三个表达式之间缺少分号分隔(如:for(i=1 i<=10 i++)),导致编译失败;
  3. do-while循环结尾遗漏分号,属于高发语法错误;
  4. 在while或do-while循环中,将循环变量的更新语句放在continue之后,导致变量无法递增,形成死循环;
  5. 多行语句未用{}包裹,导致只有第一句受循环控制,其余语句脱离循环(逻辑错误,但编译器不会报错);
  6. 在嵌套循环中混淆break或continue的作用层级,导致程序行为异常;
  7. 在循环体内人为修改for循环的循环变量,破坏原有循环次数预期。

八、goto语句

(注:原文至此结束,未提供关于goto语句的具体内容描述。)

goto 是 C 语言中的无条件跳转语句,允许在同一个函数内部直接跳转到已定义的标号位置执行代码。其核心机制在于“跳过中间代码,直接执行指定位置的语句”。

1. 基础语法与实例解析
在使用 goto 时,需先定义一个标号,格式为:标号名后跟冒号(:),例如 next:。该标号名称由用户自定义。
触发跳转的语句为:goto 标号名;,程序一旦执行此语句,便会立即跳转至对应标号所在的位置继续运行。

示例代码如下:

#include <stdio.h>
int main()
{
    printf("hehe\n");   // 第1步:执行,输出hehe
    goto next;          // 第2步:触发跳转,直接到next标号
    printf("haha\n");   // 被跳过,不会执行
next:                   // 标号位置
    printf("跳过了haha的打印!\n"); // 第3步:执行,输出内容
    return 0;
}

运行后的输出结果为:

hehe
跳过了haha的打印!

2. 典型应用场景:多层循环的高效退出
在处理嵌套循环结构时,普通的 break 语句只能终止当前所在的最内层循环,若存在三层或更深的循环嵌套,则需要多个 break 配合才能完全跳出所有层级。而使用 goto 可以一步实现多层跳出,显著提升代码简洁性与执行效率。

以下为多层循环中应用 goto 的典型逻辑示意:

for(...) // 外层循环
{
    for(...) // 中层循环
    {
        for(...) // 内层循环
        {
            if(disaster) // 满足条件时
                goto error; // 直接跳转到error标号,跳出所有循环
        }
    }
}
error: // 所有循环外的标号
// 后续处理代码

3. 使用规范与注意事项
尽管 goto 提供了灵活的控制流跳转能力,但过度或随意使用会导致程序流程难以追踪,破坏代码结构的清晰性,增加维护难度。因此,建议尽量避免使用 goto,仅在如“多层循环快速退出”等少数确实能提升可读性和效率的特殊场景下谨慎采用。

总结:goto 作为函数内部的无条件跳转工具,通过预设标号实现代码执行位置的直接转移,适用于特定情况下的流程优化,尤其是深层循环的快速退出。然而,必须严格限制其使用范围,防止造成程序逻辑混乱。

输入输出机制与流程控制构成了 C 语言编程的核心基础。深入理解各类语句的语法特点和适用场景,有助于构建条理清晰、逻辑严密的程序结构,有效预防常见编码错误。扎实掌握这些基本功,将为后续学习更复杂的编程技术奠定坚实基础,持续提升编程实践与问题解决能力。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:C语言 Hello World Expression continue Default

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-28 17:03