您的位置:首页 > 其它

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

2015-09-30 16:53 393 查看
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 是一个全局变量,其值随时可能发生变化,尽量少用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: