uc笔记02---错误处理,练习:实现求和求平均值等功能,errno

23 篇文章 0 订阅
1.    通过返回值表示错误
    1)返回合法值表示成功,返回非法值表示失败
        #include <stdio.h>
        #include <limists.h>
        long fsize (const char* path) {
            FILE* fp = fopen (path, "r");    // 失败返回 0
            if (! fp)
                return -1;
            fseek (fp, 0, SEEK_END);
            long size = ftell (fp);            // 返回字节数
            fclose (fp);
            return size;
        }
        int main () {
            printf ("文件路径:");
            char path[PATH_MAX+1];            // 最大路径长度,+1 用于 /0
            scanf ("%s", path);
            long size = fsize (path);
            if (size < 0) {
                printf ("open error\n");
                return -1;
            }
            printf ("文件大小:%ld字节\n", size);
            return 0;
        }

    2)返回有效指针表示成功;失败返回空指针或者返回 -1(0xFFFFFFFF)
        #include <stdio.h>
        #include <string.h>
        const char* strmax (const char* a, const char* b) {
            return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;
            // 防止输入 a 或者 b 为 0 或者 null;
        }
        int main () {
            const char* max = strmax ("hello", "word");
            if (! max) {
                printf ("error\n");
                return -1;
            }
            printf ("字符串最大值:%s\n", max);
            return 0;
        }
        
    3)返回 0 表示成功,返回 -1 表示失败;
        不输出数据或者通过指针/引用型参数输出数据;
        #include <stdio.h>
        int intmod (int a, int b, int* mod) {
            if (b == 0)        // 取模时,b 不能为 0
                return -1;
            *mod = a % b;
            return 0;
        }
        int main () {
            printf ("两个整数:");
            int a, b;
            scanf ("%d%d", &a, &b);
            int mod;
            if (intmod (a, b, &mod) == -1) {
                printf ("error\n");
                return -1;
            }
            printf ("取模:%d\n", mod);
            return 0;
        }

    4)永远成功
    
2.    练习:实现四个函数
    slen()        求字符串长度,若为空,则报错;
    scpy()        字符串拷贝,考虑缓冲溢出;成功返回目标缓冲区地址,目标缓冲区无效时报错;
    intmin()    求两个整数最小值,若二者相等,则报错;
    intave()    求两个整数平均值,该函数不会失败;

    #include <stdio.h>
    size_t slen (const char* s) {
        if (! s)
            return -1;
        size_t len;
        for (len = 0; s[len]; ++len);
        return len;
    }
    char* scpy (char* dst, size_t size, const char* src) {
        if (! dst || ! size)
            return NULL;
        size_t len = slen (src);
        if (-1 == len)
            return NULL;
        size_t i, chs = size-1 < len ? size-1 : len;
        for (i = 0; i < chs; ++i)
            dst[i] = src[i];
        dst[i] = '/0';
        return dst;
    }
    int intmin (int a, int b, int* min) {
        if (a == b)
            return -1;
        *min = a < b ? a : b;
        return 0;
    }
    int intave (int a, int b) {
        return (a + b) / 2;
    }
    int main () {
        size_t len = slen ("hello word");
        if (-1 == len)
            printf ("error\n");
        else
            printf ("%u\n", len);
            
        char dst[5];
        if (! scpy (dst, sizeof (dst) / sizeof (dst[0]), "0123456789"))
            printf ("error\n");
        else
            printf ("字符串副本:%s\n", dst);
        
        int min;    
        if ((intmin (-1, 0, &min) == -1)
            printf ("error\n");
        else
            printf ("%d\n", min);
            
        printf ("%d\n", intave (123, 456));
        return 0;
    }

    防止上面求和内存溢出,可以如下更改:
    int intave (int a, int b) {
        return (a & b) + ((a ^ b) >> 1);    // 实现两个数的平均数
    }
    分析:
    假如有 109 和 55 两个数;
    第一步:
    109 的二进制为:                    0 1 1 0 1 1 0 1    (a 组)
    55 的二进制为:                    0 0 1 1 0 1 1 1    (b 组)
    
    第二步:两个二进制比较
    同为 1 取 1:                    0 0 1 0 0 1 0 1    (c 组)
    
    第三步:第一步和第二步的两组二进制分别比较
    109 上面为 1,下面为 0,记作 1:    0 1 0 0 1 0 0 0    (d 组:a 组和 c 组比较)
    55 上面为 0,下面为 1,记作 1:    0 0 0 1 0 0 1 0    (e 组:b 组和 c 组比较)
    
    第四步:求和
    109 + 55 = a + b = (c + d) + (c + e)
    c + d = (109 & 55) * 2;
    c + e = 109 ^ 55;
    
    第五步:求平均数
    (c + d) / 2 = 109 & 55;
    (c + e) / 2 = (109 ^ 55) / 2 = (109 ^ 55) >> 1;
    (109 + 55) / 2 = (109 ^ 55) / 2 = (109 ^ 55) >> 1;
    所以,平均数:(a + b) / 2 = (a & b) + ((a ^ b) >> 1);
    
    109 =    01101101    =    00100101    (同为 1 取 1)    + 01001000    (上面为 1,下面为 0, 记作 1)
    55 =    00110111    =    00100101    (同为 1 取 1)    + 00010010    (上面为 0,下面为 1, 记作 1)
    109+55            =        (109&55)* 2        +    109^55
    (109+55)/2        =        109&55                +    (109^55)/2
    (109+55)/2        =        109&55                +    (109^55)>>1

3.    通过 errno 表示错误

    #include <errno.h>

    1) 根据 errno 得到错误编号。
    2) 将 errno 转换为有意义的字符串:
        #include <string.h>
        char* strerror (int errnum);
    3)直接打印错误信息:
        #include <stdio.h>
        void perror (const char* s);
    4)直接打印错误信息:
        printf ("%m");

    范例:errno.c
        #include <stdio.h>
        #include <errno.h>
        #include <string.h>
        int main () {
            FILE* fp = fopen ("none", "r");        // 构造错误,会返回 NULL
            if (! fp) {
                printf ("错误号:%d\n", errno);
                printf ("错误字符串:%s\n", strerror (errno));
                perror ("错误信息前缀");
                printf ("附加信息:%m\n");
            }
            return 0;
        }

    5)errno 在函数执行成功的情况下不会被修改,
           因此不能以 errno 非零,作为发生错误判断依据。

    范例:iferr.c
        #include <stdio.h>
        #include <errno.h>
        int main () {
            FILE* fp = fopen ("none", "r");
            fp = fopen ("/etc/passwd", "r");
            if (errno) {
                perror ("fopen");
                return -1;
            }
            fclose (fp);
            return 0;
        }

    6)errno 是一个全局变量,其值随时可能发生变化,尽量少用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值