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 是一个全局变量,其值随时可能发生变化,尽量少用。
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 是一个全局变量,其值随时可能发生变化,尽量少用。
相关文章推荐
- centos7 oracle 12c 安装问题记录
- MySQL 水平拆分
- 分布式系统概念与设计-CH1:分布式系统的特征
- QQ在线客服代码(绝对强制对话框)
- irrlicht启动两个控制台
- 分布式Hibernate search
- Jenkins:slave连不上master 问题解决方法
- 经典算法题——第十一题 Bitmap算法
- 第四次作业
- 设置window.open()在选项卡中打开页面
- Jquery on()方法 替代live(),bind()绑定事件
- 笔记本和打印机不在一个网段,无线连接打印机的方法
- Microsoft Azure 部署网站
- 测试驱动
- uc笔记01---Unix,Linux,程序构建过程,gcc,头文件,预处理,环境变量配置
- linux下U盘内容为只读文件的解决办法
- 两个队列实现一个栈
- 这是一篇纯吐槽的文章
- ASP.NET内置对象一
- Android 获取控件的宽高的靠谱方式