《C语言进阶剖析》4.条件语句与循环语句

一.《第6课 - 分支语句》

 

1. if 语句分析

(1)if 语句用于根据条件选择执行语句

      

(2)else 不能独立存在且总是与它最近的 if 相匹配,else 语句后可以连接其它if语句

(3)if 语句中零值比较的注意点,这个考点频繁出现在C语言笔试中!!!

  • bool类型  ==>  bool型变量应该直接出现在条件中,不要进行比较

            

  • 整型  ==>  变量和0值比较时,0值应该出现在比较符号左边     // 防止将 == 写成 =,那样条件永远不成立; 0放在左边,误写为 = 会编译报错

            

  • float型  ==>  因为float是不精确表示,0.0在内存中的表示可能是与其相近的一个值,所以不能直接和0值比较,需要定义精度

           

2. switch语句分析

(1)switch语句经常用在单个条件多个分支的情形

(2)case语句后面必须要有break,否则会导致分支重叠,实际工作中很多的bug就是由于忘记加break导致的!

(3)default语句有必要加上,以处理特殊情况

        

(4)case语句中的值只能整型字符型

(5)case语句的排列顺序遵照下面的规则,这样代码更加易读

  • 按字母或数字顺序排列各条语句
  • 正常情况放在前面,异常情况放在后面
  • default 语句只用于处理真正的默认情况

【if 和 switch使用示例】

#include <stdio.h>

void f1(int i)
{
    if( i < 6 )
    {
        printf("Failed!\n");
    }
    else if( (6 <= i) && (i <= 8) )
    {
        printf("Good!\n");
    }
    else
    {
        printf("Perfect!\n");
    }
}

void f2(char i)
{
    switch(i)
    {
        case 'c':
            printf("Compile\n");
            break;

        case 'd':
            printf("Debug\n");
            break;

        case 'o':
            printf("Object\n");
            break;

        case 'r':
            printf("Run\n");
            break;

        default:
            printf("Unknown\n");
            break;

    }
}

int main()
{
    f1(5);  // Failed!
    f1(9);  // Perfect!
    f1(7);  // Good!

    f2('o');  // Object
    f2('d');  // Debug
    f2('e');  // Unknown

    return 0;
}

if 和 switch有各自适用的场合,这样代码看起来逻辑更加清晰!但是if 和 switch 两者也能进行转换,将前面的代码进行转换......

【有趣的角色互换】

#include <stdio.h>

void f1(int i)
{
    switch( i < 6 )
    {
        case 1:
            printf("Failed!\n");
            break;

        default:
            switch( (6 <= i) && (i <= 8) )
            {
                case 1:
                    printf("Good!\n");
                    break;

                default:
                    printf("Perfect!\n");
                    break;
            }
            break;
    }
}

void f2(char i)
{
    if( 'c' == i )
    {
        printf("Compile\n");
    }
    else if( 'd' == i )
    {
        printf("Debug\n");
    }
    else if( 'o' == i )
    {
        printf("Object\n");
    }
    else if( 'r' == i )
    {
        printf("Run\n");
    }
    else
    {
        printf("Unknown\n");
    }
}

int main()
{
    f1(5);  // Failed!
    f1(9);  // Perfect!
    f1(7);  // Good!

    f2('o');  // Object
    f2('d');  // Debug
    f2('e');  // Unknown

    return 0;
}


二.《第7课 - 循环语句》

 

1. 循环语句分析

(1)循环语句的基本工作方式

  • 通过条件表达式判定是否执行循环体
  • 条件表达式遵循 if 语句表达式的原则

(2)do、while、for的区别

  • do 语句先执行后判断,循环体至少执行一次
  • while 语句先判断后执行,循环体可能不被执行
  • for 语句先判断后执行,相比while更简洁

2. 循环的回顾

  

【三种循环语句使用对比】

#include <stdio.h>

int f1(int n)
{
    int ret = 0;

    if( n > 0 )
    {
        do
        {
            ret += n;
            n--;
        }
        while( n > 0 );
    }

    return ret;
}

int f2(int n)
{
    int ret = 0;

    while( n > 0 )
    {
        ret += n;
        n--;
    }

    return ret;
}

int f3(int n)
{
    int ret = 0;
    int i = 0;

    for(i=1; i<=n; i++)
    {
        ret += i;
    }

    return ret;
}

int main()
{
    printf("%d\n", f1(100));  // 5050
    printf("%d\n", f2(100));  // 5050
    printf("%d\n", f3(100));  // 5050

    return 0;
}

3. break和continue的区别

(1)break表示终止循环的执行,跳出整个循环

(2)continue表示终止本次循环,进入下次循环

【break和continue的区别】

#include <stdio.h>

void f1(int n)
{
    int i = 0;

    for(i=1; i<=n; i++)
    {
        if( (i % 2) == 0 )
        {
            break;  // 跳出循环
        }

        printf("%d ", i);
    }

    printf("\n");
}

void f2(int n)
{
    int i = 0;

    for(i=1; i<=n; i++)
    {
        if( (i % 2) == 0 )
        {
            continue;   // 终止本次循环,进入下次循环
        }

        printf("%d ", i);
    }

    printf("\n");
}

int main()
{
    f1(10);  // 1
    f2(10);  // 1 3 5 7 9

    return 0;
}

【do...while(0)和break的妙用】

#include <stdio.h>
#include <malloc.h>

int func(int n)
{
    int i = 0;
    int ret = 0;
    int* p = (int*)malloc(sizeof(int) * n);

    do
    {
        if( NULL == p ) break;  // 注意这里break的用法

        if( n < 5 ) break;

        if( n > 100) break;

        for(i=0; i<n; i++)
        {
            p[i] = i;
            printf("%d\n", p[i]);
        }

        ret = 1;
    }while( 0 );

    printf("free(p)\n");

    free(p);    // 在任何情况下,free(p)都会被执行,不会泄露内存

    return ret;
}

int main()
{
    if( func(4) )
    {
        printf("OK\n");
    }
    else
    {
        printf("ERROR\n");
    }

    return 0;
}


三.《第8课 - goto和void分析》

 

1. 遭人嫌弃的goto

(1)高手潜规则:禁用goto

(2)项目经验:程序质量与goto的出现次数成反比;c语言是一门结构化语言,goto会破坏C语言的结构化特性。

(3)最后的判决:将goto打入冷宫

【goto副作用分析】

#include <stdio.h>
#include <malloc.h>

void func(int n)
{
    int* p = NULL;

    if(  n < 0 )
    {
        goto STATUS;
    }

    p = (int*)malloc(sizeof(int) * n);  // 当 n<0 时不执行这行

STATUS:
    p[0] = n;    // n<0 时,p为野指针,会产生段错误

    free(p);
}

int main()
{
    printf("begin...\n");

    printf("func(1)\n");
    func(1);

    printf("func(-1)\n");
    func(-1);

    printf("end...\n");

    return 0;
}

2. void的意义

2.1 void修饰函数返回值和参数

(1)void 修饰函数返回值和参数是为了表示 "无"

(2)如果函数没有返回值,那么应该将其声明为void;否则编译器默认返回值类型为int

(3)如果函数没有参数,应该声明其参数为void;否则编译器默认函数可以传递任意多个参数

#include <stdio.h>

/*
// 若函数没有返回值,编译器默认返回值为int类型
// 若函数没有参数,编译器默认函数可以传递任意个参数
f()
{

}
*/

void f(void)   // 函数没有返回值,不接受参数
{

}

int main()
{
    // int i = f(1, 2, 3);

    return 0;
}

2.2 不存在void变量

C语言没有定义void究竟是多大内存的别名,因此没有void的标尺,无法在内存中裁剪出void对应的变量(void只是一种抽象的类型)。

#include <stdio.h>

int main()
{
    // void var;    // error
    // void array[5];   // error

    void *pv;   // 指针要么为4字节,要么为8字节,可以定义void类型的指针变量

    return 0;
}

小贴士:

ANSI C:标准C语言的规范

扩展C:编译器厂商在ANSI C的基础上进行了扩充,像我们平时使用的gcc、VS编译器就是使用的扩展C

【void在ANSI C和扩展C中的区别】

#include <stdio.h>

int main()
{
    printf("cc sizeof(void) = %zu\n", sizeof(void));    // 在ANSI C编译器中编译无法通过
                                                        // 在支持GNU标准的gcc编译器中编译通过,结果为1

    return 0;
}

bcc32编译器(使用ANSI C标准)  ==>   编译失败

  

gcc编译器  ==>  编译通过

  

2.3 void指针的意义

(1)C语言规定只有相同类型的指针才可以相互赋值

(2)void *指针作为左值用于接收任意类型的指针

(3)void *指针作为右值使用时需要进行强制类型转换

     

【通过void*实现MemSet函数】

#include <stdio.h>

void MemSet(void* src, int length, unsigned char n)
{
    unsigned char* p = (unsigned char*)src;

    int i = 0;

    for(i=0; i<length; i++)
    {
        p[i] = n;
    }
}

int main()
{
    int a[5]; // char a[5] double a[5]
    int i = 0;

    MemSet(a, sizeof(a), 0);

    for(i=0; i<5; i++)
    {
        printf("%d\n", a[i]);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值