Bootstrap

Linux和C语言(Day05)

一、学习内容

  1. 循环结构

    1. 四种循环

                重复结构,反复的执行某一部分代码。 C语言中提供了四种循环方式——非标准的goto循环,标准的while循环、do-while循环、for循环。其中goto循环会改变程序流程走向,是有害的,不建议使用,但是高级语言又应该保留goto语句。 四种循环语句是可以相互转换的,但是自身又是有区别的,具体的区别看下面。

  1. goto循环
    1. Loop: if(){ 执行语句; goto Loop; }

    2. 执行逻辑:遇见goto,回到goto执行的地方。

  2. while循环
    1. while(表达式){ 循环体; }

    2. 执行逻辑:先判断while()表达式为真,执行循环体;为假,不执行。

  3. do-while循环
    1. do{ 循环体; }while(表达式);

    2. 执行逻辑:先执行循环体,再判断while()表达式,表达式为真,继续执行循环体;为假,不执行。

  4. for循环
    1. for(表达式1; 表达式2; 表达式3){ 循环体; }

    2. 表达式1:初始值/起始值 i=1 i=0 i=20 表达式2:循环控制条件 i<=10 i<100 i<10 表达式3:增量变化 i++ i+=2 i++

    3. 执行逻辑:表达式1 --> 表达式2 --为真--> 循环体 --> 表达式3 --> 表达式2 --为真--> 循环体 --为假--> 结束 --为假--> 结束

  5. 1、循环有两种控制方式:计数控制 和 条件控制 eg: 三次密码验证 VS 输入密码直到正确登录为止 买5个苹果 【计数】 买10斤苹果 【条件】

    2、循环有两种实现方式:当型循环 和 直到型循环 当型循环:先判断再执行 while for 直到型循环:先执行再判断 do-while

    3、循环语句可以相互转换、相互嵌套

    4、while和do-while的区别? ①语法不一样 ②while先判断再执行,最少执行0次;do-while先执行再判断,最少执行1次

    5、for循环的注意事项 for(表达式1; 表达式2; 表达式3),表达式1 2 3都可以省略,两个分号不可以省略 for(;;) 死循环 for(;1;) 死循环 for(;0;) 不执行

    6、如何选用循环 计数控制循环优先选用 for 结构最简单 条件控制循环可以选用 while 询问是否继续输入选用 do-while 不建议使用goto实现循环

    7、goto和while、for循环的区别

    goto不是一个循环,跳转,会影响代码的可读性

    while适用于已知条件的循环

    for适用于已知次数的循环

    1. 控制语句

      1. break语句
        1. break 终止 中断

        2. 作用:①跳出switch语句 ②跳出while do-while for循环语句,结束靠近它的的那一层循环

        3. 注意:不能单独加在if语句中

      2. continue语句
        1. continue 继续

        2. 作用:用于while do-while for循环,表示跳过本次循环,继续下一次循环

      3. return语句
        1. return 返回

        2. 作用:结束函数

    2. 循环嵌套

      1. 在一个循环中还嵌套另外一个循环。

      2. 嵌套格式:
        for+for for+while for+dowhile
        while+for while+while while+dowhile
        dowhile+for dowhile+while dowhile+dowhile

        3.脑图:

二、作业

  1. 考虑到多重循环对程序效率的影响,以下哪种实现效率较高?为什么?(泰华智慧)

(a)循环次数大的放在外层,循环次数小的放在内层;

(b)循环次数小的放在外层,循环次数大的放在内层;

解析:

 时间复杂度:假设有两个嵌套的循环,外层循环迭代 m 次,内层循环迭代 n 次。整个程序的运行时间复杂度为 O(m * n)。如果 m 比 n 小,那么内层循环的开销会被重复 m 次,而外层循环只执行 n 次。因此,将较小的循环放在外层,可以减少总体的计算量。

解答:

(b)

  1. 2.请简述以下两个 for 循环的优缺点。(山大华天,登虹科技)        

  2. (1)、
    for(i=0; i<N; i++)
    {
        if(condition)
            DoSomething();
        else
            DoOtherthing();
    }
    (2)、
    if(condition)
    {
        for(i=0; i<N; i++)
            DoSomething();
    }
    else
    {
        for(i=0; i<N; i++)
            DoOtherthing();
    }

    解析:

  3. 这两个 `for` 循环结构在性能和逻辑上的优缺点可以从以下几个方面来分析:

    1. 结构 (1) 的优缺点

    优点:

    -简单直观:这个结构更简单明了,无需额外的条件判断来控制不同的循环行为。

    -条件变化处理:每次迭代中都会检查 `condition`,这样可以处理动态变化的条件情况(假如 `condition` 在循环内可能会改变)。

    缺点:

    - 条件检查开销:每次迭代中都要进行条件检查,这可能会增加不必要的开销,尤其是 `N` 很大的时候。

    - 性能不稳定:如果 `DoSomething()` 和 `DoOtherthing()` 的执行时间相差很大,这种结构可能会导致性能不稳定,特别是在 `condition` 经常切换的情况下。

    2. 结构 (2) 的优缺点

    优点:

    减少条件检查开销:只需要在循环开始之前进行一次条件检查,这样每次迭代中不再需要重复条件判断,从而减少了开销。

    -性能优化:如果 `DoSomething()` 和 `DoOtherthing()` 执行时间相差较大,这种结构可以将条件检查与循环分离,从而优化性能。

    缺点:

    -不适合动态条件:如果 `condition` 在循环过程中可能会发生变化,这种结构将无法适应动态变化的条件,因为循环体始终是固定的。

    - 复杂度增加:对于复杂的条件和循环,可能需要额外的代码来处理不同的情况,使得代码的逻辑更加复杂。

    总结

    - 选择 (1)当你需要每次迭代中都对 `condition` 进行检查时,特别是在 `condition` 可能会动态变化的情况下。

    - 选择 (2) 当 `condition` 在循环开始时是静态的,并且你希望通过减少条件检查的开销来优化性能时。

  4. do-while语句的循环体( ) (鲁科安全) 

    A. 可能一次都不执行           B. 至少执行一次

    C. 由循环条件决定次数       D. BC均正确

解析:

do-while 语句的特点是循环体 至少执行一次。这是因为 do-while 循环在每次循环迭代之前都会检查循环条件,而循环体在条件检查之前已经执行了一次。

解答:

D

    5.求1~100的和,写作for(int s=0,i=1;________;++i) ________;(富士安全)

解析:

int i = 1:初始化循环变量 i 为 1。i <= 100:循环条件,当 i 小于或等于 100 时继续执行循环。++i:在每次循环结束时,将 i 增加 1。sum += i:将 i 的值累加到 sum 中。

解答:

i<=100
s+=i 

        6.程序如下,运行结果为:(中科四平)

  1. #include <stdio.h>
    #define N 4
    void main()
    {
        int i;
        int x1=1,x2=2;
        printf("\n");
        for(i=1;i<=N;i++)
        {
            printf("%4d%4d",x1,x2);
            if(i%2==0)
            printf("\n");
            x1=x1+x2; //3 8 21
            x2=x2+x1; //5 13 34
        }
    }

    解析:

  2. int x1 = 1, x2 = 2;:初始化两个变量 x1x2,分别为 1 和 2。printf("\n");:输出一个换行符,以确保输出的开始位置在新的一行。for(i = 1; i <= N; i++):循环 N 次(这里 N 的值是 4)。在每次循环中,程序执行以下操作:printf("%4d%4d", x1, x2);:以宽度为 4 的字段宽度打印 x1x2 的值。if(i % 2 == 0) printf("\n");:每当 i 为偶数时(即每两次循环),打印一个换行符。x1 = x1 + x2;:更新 x1 的值为 x1 + x2x2 = x2 + x1;:更新 x2 的值为 x2 + x1

解答:


最终输出:   1   2  3   5
                      8  13 21  34

改进版输出斐波那契

        7.有以下程序段,int k=0; while(k=1) k++;则while循环执行的次数是( ) (杭州快越科技,山东大齐通讯,山东信通电子)

  1. A. 一次也不执行                    B. 执行1次
  2. B. 有语法错,不能执行       D. 无限次

解析:

While语句,最开始i=0;i<10为true,进入循环体,进入判断语句if(i<1)判断为真,所以执行continue

Continue语句被执行,这会跳过剩下的循环体部分(包括 i++)并回到循环开始的位置。所以i一直为0,程序进入死循环

解答:

D

        8.语句while(!E)中表达式!E等价于( ) (杭州快越科技)

A.E == 1                   B. E != 0           C. E != 1           D. E==0

解析:

在 `while(!E)` 语句中,`!E` 是 `E` 的逻辑非运算符。它的作用是将 `E` 的布尔值取反,即如果 `E` 为 `true`(非零),`!E` 为 `false`(0);如果 `E` 为 `false`(0),`!E` 为 `true`(非零)。

等价关系分析

`!E` 为 `true` 当 `E` 为 0。

`!E` 为 `false` 当 `E` 为 非零值。

所以,`while(!E)` 语句中的 `!E` 其实是判断 `E` 是否为 0。也就是说:

当 `E` 为 0 时,`!E` 为 `true`,`while(!E)` 条件满足,循环继续。

当 `E` 不为 0 时,`!E` 为 `false`,`while(!E)` 条件不满足,循环终止。

因此,`!E` 等价于 `E == 0`。

解答:

D

        9.goto语句有什么作用?(深圳元征信息科技)

解析:

 无条件跳转:goto 语句通过跳转到程序中的标签位置,可以使控制流直接跳到标记的代码行。

跳过代码:它可以跳过不需要执行的代码,特别是在复杂的条件分支和循环中。错

误处理:在一些情况下,goto 可以用来实现错误处理和清理代码。例如,在函数中进行资源释放操作时,使用 goto 可以避免重复的代码。

        10.语句for( ;1 ;) 有问题吗?它是什么作用?(深圳元征信息科技)

解析:

没问题,for(;1;)相当于while(1){} 是一种创建无限循环的简洁方式也就是死循环

        11.下面代码是否有错,如果有,错在哪里?(深圳元征信息科技)

  1. int main()
    {
       float a=3;
        switch(a)
        {
          case 3:
             printf("a");
        }
        return 0;
    }

    解析:

  2. 有错,错在对a的定义上,因为swith和case标签后面跟的都是整型表达式或,而float定义的浮点型

    1.         12.break 语句的正确的用法是 ( ) (福建新大陆)

A.无论在任何情况下,都中断程序的执行,退出到系统下一层

B. 在多重循环中,只能退出最靠近的那一层循环语句

C. 跳出多重循环

D. 只能修改控制变量

解析:

A.

这是错误的。break 语句只退出其所在的循环或 switch 语句,而不是整个程序或系统。

 B.

这是正确的。break 语句只能退出它所在的那一层循环或 switch 语句。如果有嵌套的循环结构,break 只影响最内层的循环或 switch 语句。

 C.

这是不准确的。break 语句不能直接跳出多重循环结构中的所有层次。如果需要退出多层循环,可以使用标志变量或 goto 语句(尽管 goto 一般不推荐使用)。

D.

这是错误的。break 语句不涉及修改控制变量,它的作用是终止循环或 switch 语句的执行。

解答:

B

        13.若输入 B,则以下程序运行后的输出结果是 ( ) (智洋创新)

  1. int main(void)
    {
        char grade;
        scanf("%c", &grade);
        switch (grade)
        {
            case 'A':
                                printf(">=85");
            case 'B':
            case 'C':
                                printf(">=60") :
                       case 'D':
                printf("<60");
            default:
                printf("error.");
        }
    }
    A. error. B. >=60   C. >=85   D. >=60<60error.

    解析:

  2. Case击穿,因为输入的B所以进入case’B’,然后进入case’C’由于没有break;跳出循环,所以一直向下执行程序,从而一步一步打印’>=60<60error.’

解答:
D

        14.下列各个错误中,哪一个不属于编译错误 ( ) (苏州特点电子科技)

  1. A. 改变x 原值 3 为 5 ,写作“ x==5 ;”
  2. B. 花括号不配对
  3. C. 复合语句中的最后一条语句后未加分号
  4. D. 变量有引用、无定义

解析:

A.

这是一个逻辑错误而非编译错误。x == 5; 是一个比较操作,判断 x 是否等于 5,但没有执行任何操作。编译器不会报错,但代码不会按照预期执行。因此,这不是编译错误。

B.

这会导致编译错误。编译器会因为括号不匹配而报错。

C.

如果复合语句中的最后一条语句没有分号,那么编译器会报错。因此,这也是一个编译错误。

D.

这是典型的编译错误。如果变量在引用时没有定义,编译器会报出未定义的标识符错误。

解答:

A

        15.下面代码的功能是输出以下形式的金字塔图案是:(华三外协,紫光云数,新华三)

*

***

*****

*******

int  i, j;

for(i = 1; i<= 4; i++)

{

        for(j = 1; j<= 4 - i; j++)

        {

            printf(“ “);

        }

        for(j = 1; j <= _______; j++)

        {

            printf(“*”);

        }

        printf(“\n”);

}

在下划线处应填入的是:(  )

A. i           B. 2 * i - 1                  C. 2 * i + 1                 D. i + 2

解析:

A.

如果填入 i,那么每行的星号数量将是 1, 2, 3, 4,这不符合题目要求的金字塔形状。

B.

填入 2 * i - 1,将得到 1, 3, 5, 7,这正好符合题目要求的金字塔形状。

C.

填入 2 * i + 1,将得到 3, 5, 7, 9,比要求的星号数量多出两个,不符合要求。

 D.

填入 i + 2,将得到 3, 4, 5, 6,这也不符合题目要求。

解答:

B

        16.请实现如下功能:(威海精讯畅通)

输入一排n个数,第一个数为后面所有的数的个数。统计这后面所有数中,正数、零和负数的个数。

输入:

XXX

输出:

正数个数:XXX

零个数:XXX

负数个数:XXX

示例:

输入 7 -2 0 6 5 -3.2 0 2.5

程序输出 正数个数:3

零个数:2

负数个数:2

  1. 解答:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{

    int n, i;
    int positiveCount = 0, zeroCount = 0, negativeCount = 0;
    float num;

    // 读取第一个数,即后面要处理的数的个数
    scanf("%d", &n);

    // 读取后面的 n 个数并统计正数、零和负数的个数
    for (i = 0; i < n; i++) {
        scanf("%f", &num);
        if (num > 0) {
            positiveCount++;
        } else if (num == 0) {
            zeroCount++;
        } else {
            negativeCount++;
        }
    }

    // 输出结果
    printf("正数个数:%d\n", positiveCount);
    printf("零个数:%d\n", zeroCount);
    printf("负数个数:%d\n", negativeCount);

	return 0;
}

        17.请实现一下功能:(威海精讯畅通)

输入任意两个数,输出两数之间(包括这两个数)偶数之和。

输入:

XXX XXX

输出:

XXX 到XXX偶数之和为:XXX

示例:

输入 1 10

程序输出 1到10偶数之和为:30

解答:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
	int a,b;
	scanf("%d %d",&a ,&b);
	int i=a;
	int sum=0;
	for(i=a;i<=b;i++){
		if(i%2 == 0){
			sum +=i;
		}
	}
	printf("%d到%d之间偶数之和为:%d\n",a ,b ,sum);
	return 0;
}

18.编程求 2000 以内的所有“完数”。所“完”是指一个数恰好等于它的因子值之和,例如:6是完数,因为 6=1+2+3。 (戈尔特西斯)

解答:

#include <stdio.h>

int main() {
    int perfectNumbers[10];  // 假设2000以内最多有10个完数
    int count = 0;  // 用于记录完数的个数

    // 遍历1到2000的所有数字
    for(int num = 1; num <= 2000; num++) {
        int sum = 0;

        // 找出num的所有因子
        for(int i = 1; i <= num / 2; i++) {
            if(num % i == 0) {
                sum += i;  // 将因子加到sum中
            }
        }

        // 如果因子之和等于num,则num是完数
        if(sum == num) {
            perfectNumbers[count] = num;
            count++;
        }
    }

    // 输出所有找到的完数
    printf("2000以内的完数有:\n");
    for(int i = 0; i < count; i++) {
        printf("%d\n", perfectNumbers[i]);
    }

    return 0;
}

        19.完成一个 32 位整数型数按 10 进制倒置的程序;当越界后返回值为 0。 (北京君正集成电路)

例如: 输入 1234;输出为 4321

输入-1234;输出为-4321

输入为 1023456789,输出为 0

 解答:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, const char *argv[])
{
	int a=0;
	printf("请输入一个数字\n");
	scanf("%d",&a);
	if(a > INT_MAX/10 || a < INT_MIN){
		printf("输入错误\n");
		return 0;
	}
	int sum=0;
	while(a != 0){
		int ys=a%10;
		a = a/10;
		sum =sum*10+ys;
	}
	printf("%d \n",sum);
	return 0;
}

三、总结

注意事项:

循环条件:确保循环条件会在某个时刻变为假,避免死循环。

代码可读性:避免在for循环中使用复杂表达式,保持代码简洁明了。

资源管理:在循环中注意资源释放与管理,避免占用过多系统资源。

运用方法总结:

for循环:用于需要明确控制循环次数的场景,如遍历数据集。

while循环:用于条件控制场景,如用户输入验证。

do-while循环:用于需要至少执行一次的场景,如菜单操作提示。

goto循环:除非特殊需要,通常使用其他循环结构替代。

循环的控制方式

计数控制:用于已知循环次数的场景,优先选用for循环。

条件控制:用于循环次数未知,需根据条件判断的场景,常用whiledo-while循环。

 当型循环与直到型循环

当型循环:先判断条件再执行循环体,常用于whilefor循环。

直到型循环:先执行循环体再判断条件,常用于do-while循环。

;