- C编程教程
- C语言 - 首页
- C语言基础
- C语言 - 概述
- C语言 - 特性
- C语言 - 历史
- C语言 - 环境搭建
- C语言 - 程序结构
- C语言 - Hello World
- C语言 - 编译过程
- C语言 - 注释
- C语言 - 词法单元
- C语言 - 关键字
- C语言 - 标识符
- C语言 - 用户输入
- C语言 - 基本语法
- C语言 - 数据类型
- C语言 - 变量
- C语言 - 整数提升
- C语言 - 类型转换
- C语言 - 类型强制转换
- C语言 - 布尔值
- C语言中的常量和字面量
- C语言 - 常量
- C语言 - 字面量
- C语言 - 转义序列
- C语言 - 格式说明符
- C语言中的运算符
- C语言 - 运算符
- C语言 - 算术运算符
- C语言 - 关系运算符
- C语言 - 逻辑运算符
- C语言 - 位运算符
- C语言 - 赋值运算符
- C语言 - 一元运算符
- C语言 - 自增和自减运算符
- C语言 - 三元运算符
- C语言 - sizeof 运算符
- C语言 - 运算符优先级
- C语言 - 其他运算符
- C语言中的决策语句
- C语言 - 决策语句
- C语言 - if 语句
- C语言 - if...else 语句
- C语言 - 嵌套 if 语句
- C语言 - switch 语句
- C语言 - 嵌套 switch 语句
- C语言中的循环
- C语言 - 循环
- C语言 - while 循环
- C语言 - for 循环
- C语言 - do...while 循环
- C语言 - 嵌套循环
- C语言 - 无限循环
- C语言 - break 语句
- C语言 - continue 语句
- C语言 - goto 语句
- C语言中的函数
- C语言 - 函数
- C语言 - 主函数
- C语言 - 按值调用函数
- C语言 - 按引用调用函数
- C语言 - 嵌套函数
- C语言 - 变参函数
- C语言 - 用户自定义函数
- C语言 - 回调函数
- C语言 - 返回语句
- C语言 - 递归
- C语言中的作用域规则
- C语言 - 作用域规则
- C语言 - 静态变量
- C语言 - 全局变量
- C语言中的数组
- C语言 - 数组
- C语言 - 数组的特性
- C语言 - 多维数组
- C语言 - 将数组传递给函数
- C语言 - 从函数返回数组
- C语言 - 变长数组
- C语言中的指针
- C语言 - 指针
- C语言 - 指针和数组
- C语言 - 指针的应用
- C语言 - 指针运算
- C语言 - 指针数组
- C语言 - 指向指针的指针
- C语言 - 将指针传递给函数
- C语言 - 从函数返回指针
- C语言 - 函数指针
- C语言 - 指向数组的指针
- C语言 - 指向结构体的指针
- C语言 - 指针链
- C语言 - 指针与数组
- C语言 - 字符指针和函数
- C语言 - NULL 指针
- C语言 - void 指针
- C语言 - 悬空指针
- C语言 - 解引用指针
- C语言 - 近、远和巨大指针
- C语言 - 指针数组的初始化
- C语言 - 指针与多维数组
- C语言中的字符串
- C语言 - 字符串
- C语言 - 字符串数组
- C语言 - 特殊字符
- C语言结构体和联合体
- C语言 - 结构体
- C语言 - 结构体和函数
- C语言 - 结构体数组
- C语言 - 自引用结构体
- C语言 - 查找表
- C语言 - 点(.)运算符
- C语言 - 枚举(enum)
- C语言 - 结构体填充和打包
- C语言 - 嵌套结构体
- C语言 - 匿名结构体和联合体
- C语言 - 联合体
- C语言 - 位域
- C语言 - typedef
- C语言中的文件处理
- C语言 - 输入输出
- C语言 - 文件I/O (文件处理)
- C语言预处理器
- C语言 - 预处理器
- C语言 - 预处理指令
- C语言 - 预处理器运算符
- C语言 - 宏
- C语言 - 头文件
- C语言中的内存管理
- C语言 - 内存管理
- C语言 - 内存地址
- C语言 - 存储类别
- 其他主题
- C语言 - 错误处理
- C语言 - 可变参数
- C语言 - 命令执行
- C语言 - 数学函数
- C语言 - static 关键字
- C语言 - 随机数生成
- C语言 - 命令行参数
- C编程资源
- C语言 - 问答
- C语言 - 快速指南
- C语言 - 速查表
- C语言 - 有用资源
- C语言 - 讨论
C语言错误处理
C语言本身并不直接支持错误处理,因为C语言中没有可以防止错误或异常突然终止程序的关键字。但是,程序员可以使用其他函数进行错误处理。
您可以使用errno高效地处理C语言中的错误。此外,还可以使用其他函数进行错误处理,例如perror、strerror、ferror和clearerr。
errno变量
C语言是一种系统编程语言。它以返回值的形式提供对底层的访问。大多数C语言甚至Unix函数调用在发生任何错误时返回-1或NULL,并设置错误代码errno。它被设置为全局变量,指示在任何函数调用期间发生错误。您可以在<error.h>头文件中找到各种已定义的错误代码。
因此,C程序员可以检查返回值,并根据返回值采取适当的操作。最好在程序初始化时将errno设置为0。值为0表示程序中没有错误。
下表显示了errno值及其关联的错误消息:
| errno值 | 错误 |
|---|---|
| 1 | 操作不被允许 |
| 2 | 没有这样的文件或目录 |
| 3 | 没有这样的进程 |
| 4 | 系统调用中断 |
| 5 | I/O错误 |
| 6 | 没有这样的设备或地址 |
| 7 | 参数列表太长 |
| 8 | 可执行文件格式错误 |
| 9 | 错误的文件编号 |
| 10 | 没有子进程 |
| 11 | 请重试 |
| 12 | 内存不足 |
| 13 | 权限被拒绝 |
示例
请看下面的例子:
#include <stdio.h>
#include <errno.h>
int main() {
FILE* fp;
// opening a file which does not exist
fp = fopen("nosuchfile.txt", "r");
printf("Value of errno: %d\n", errno);
return 0;
}
输出
它将产生以下输出:
Value of errno: 2
C语言提供perror()和strerror()函数,可以用来显示与errno相关的文本消息。
perror()函数
显示您传递给它的字符串,后跟一个冒号、一个空格,然后是当前errno值的文本表示。
void perror(const char *str);
示例
在上面的例子中,“errno = 2”与消息没有这样的文件或目录相关,可以使用perror()函数打印。
#include <stdio.h>
#include <errno.h>
int main(){
FILE* fp;
// opening a file which does not exist
fp = fopen("nosuchfile.txt", "r");
printf("Value of errno: %d\n", errno);
perror("Error message:");
return 0;
}
输出
运行此代码时,将产生以下输出:
Value of errno: 2 Error message: No such file or directory
strerror()函数
这将返回一个指向当前errno值文本表示的指针。
char *strerror(int errnum);
让我们使用此函数显示errno=2的文本表示:
示例
请看下面的例子:
#include <stdio.h>
#include <errno.h>
int main() {
FILE* fp;
// opening a file which does not exist
fp = fopen("nosuchfile.txt", "r");
printf("Value of errno: %d\n", errno);
printf("The error message is : %s\n", strerror(errno));
return 0;
}
输出
Value of errno: 2 he error message is : No such file or directory
ferror()函数
此函数用于检查文件操作期间是否发生错误。
int ferror(FILE *stream);
示例
在这里,我们尝试从以“w”模式打开的文件中读取。ferror()函数用于打印错误消息。
#include <stdio.h>
int main(){
FILE *fp;
fp = fopen("test.txt","w");
char ch = fgetc(fp); // Trying to read data, from writable file
if(ferror(fp)){
printf("File is opened in writing mode! You cannot read data from it!");
}
fclose(fp);
return(0);
}
输出
运行代码并检查其输出:
File is opened in writing mode! You cannot read data from it!
clearerr()函数
clearerr()函数用于清除文件流的EOF和错误指示符。
void clearerr(FILE *stream);
示例
请看下面的例子:
#include <stdio.h>
int main(){
FILE *fp;
fp = fopen("test.txt","w");
char ch = fgetc(fp); // Trying to read data, from writable file
if(ferror(fp)){
printf("File is opened in writing mode! You cannot read data from it!\n");
}
// Clears error-indicators from the file stream
// Subsequent ferror() doesn't show error
clearerr(fp);
if(ferror(fp)){
printf("Error again in reading from file!");
}
fclose(fp);
return(0);
}
除零错误
一个常见问题是,在除法运算时,程序员不检查除数是否为零,最终导致运行时错误。
示例1
以下代码通过在除法之前检查除数是否为零来修复此错误:
#include <stdio.h>
#include <stdlib.h>
int main() {
int dividend = 20;
int divisor = 0;
int quotient;
if( divisor == 0){
fprintf(stderr, "Division by zero! Exiting...\n");
exit(-1);
}
quotient = dividend / divisor;
fprintf(stderr, "Value of quotient : %d\n", quotient );
exit(0);
}
输出
编译并运行上述代码时,将产生以下结果:
Division by zero! Exiting... Program Exit Status
通常的做法是在程序成功操作后退出时使用EXIT_SUCCESS值。这里,EXIT_SUCCESS是一个宏,定义为0。
示例2
如果您的程序中存在错误条件并且您要退出,则应使用EXIT_FAILURE状态退出,该状态定义为“-1”。所以让我们将上面的程序改写如下:
#include <stdio.h>
#include <stdlib.h>
int main() {
int dividend = 20;
int divisor = 5;
int quotient;
if(divisor == 0) {
fprintf(stderr, "Division by zero! Exiting...\n");
exit(EXIT_FAILURE);
}
quotient = dividend / divisor;
fprintf(stderr, "Value of quotient: %d\n", quotient );
exit(EXIT_SUCCESS);
}
输出
编译并运行上述代码时,将产生以下结果:
Value of quotient: 4