C语言里面的中断程序:“exit()”和“return返回”

完整示例代码在文章末尾,示例代码来自《C Primer Plus》第17章程序清单17.4(films3.c)的源代码。

films3.c 代码中,出现了exit(EXIT_FAILURE)和return 0语句,下面是为什么初始化阶段用了 exit(EXIT_FAILURE),而 main 函数末尾用了 return 0的原因,并说明 exit()return 的区别。

为什么初始化阶段用 exit(EXIT_FAILURE)

这段代码:

c 复制代码
InitializeList(&movies);
if (ListIsFull(&movies))
{
    fprintf(stderr, "No memory available! Bye!\n");
    exit(EXIT_FAILURE);
}

放在程序刚开始、链表刚初始化之后。它的目的是检测严重错误(内存不足)并立即终止程序

  • InitializeList() 内部通常会尝试分配链表头节点的内存。
  • 如果分配失败(极少见,但理论上可能),链表会被标记为"满"(在本书的实现中,初始化失败时会把列表设为满状态来表示错误)。
  • 一旦发生这种情况,程序根本无法继续运行(后续所有添加电影的操作都会失败),所以直接终止程序是最合理的选择。
  • 使用 exit(EXIT_FAILURE) 可以立即结束整个程序,不需要再执行后面的输入、显示等代码。

这是一种防御性编程做法:尽早发现无法恢复的错误,就立刻停止,避免程序进入无效状态继续运行产生误导性结果。

为什么 main 函数末尾用 return 0

c 复制代码
return 0;

这是程序正常结束时的标准写法,表示:

  • 一切顺利(用户输入完成,列表显示完毕,可选的清理也做了)。
  • 向操作系统返回状态码 0(惯例表示"成功")。

这是最常规、最推荐的结束 main 函数的方式。

exit()return 的区别

方面 return(在 main 中) exit()
作用范围 只从当前函数返回控制权。 在 main 中返回相当于结束程序。 立即终止整个程序,不管当前在哪个函数(哪怕嵌套很深)。
执行位置 只能在函数体内使用,返回到调用者。 可以在程序任何地方调用(包括库函数、嵌套函数)。
清理行为 mainreturn n; 会: 1. 刷新标准I/O缓冲区 2. 调用 atexit() 注册的函数 3. 向OS返回 n (与 exit(n) 效果几乎相同) 同样会: 1. 调用 atexit() 注册的函数 2. 刷新标准I/O缓冲区 3. 关闭打开的文件 4. 向OS返回状态码
主要差异 更"局部",强调"本函数正常结束"。 在 main 中推荐使用。 更"全局",强调"强制立即终止程序"。 常用于错误处理或深层函数中需要立刻退出整个程序的情况。
可移植性和习惯 main 中写 return 0; 是C标准推荐的正常结束方式。 exit() 来自 <stdlib.h>,常用于异常情况。 exit(EXIT_SUCCESS)exit(EXIT_FAILURE) 是标准宏。
从非 main 函数返回 如果在其他函数里用 return,只会返回到调用者,程序继续运行。 无论在哪里调用 exit(),程序都会立即结束。

总结区别的实际意义

  • 如果你在 main 中正常结束,用 return 0; 更清晰、符合习惯。
  • 如果在程序早期或深层函数发现无法恢复的致命错误 ,用 exit(EXIT_FAILURE) 可以立刻停止整个程序,避免继续执行无意义的代码。

在《C Primer Plus》这本书的例子中,这里用 exit() 是为了教学目的:展示如何处理内存分配失败这种严重错误,同时演示 exit() 的用法。如果把这部分改成 return EXIT_FAILURE;,效果也几乎一样(因为在 main 中),但用 exit() 更突出"立即终止"的意图。

完整示例代码:

c 复制代码
/* films3.c -- using an ADT-style linked list */
/* compile with list.c */

#include <stdio.h>
#include <stdlib.h>    /* prototype for exit() */
#include "list.h"      /* defines List, Item */

void showmovies(Item item);

int main(void)
{
    List movies;
    Item temp;

    /* initialize */
    InitializeList(&movies);
    if (ListIsFull(&movies))
    {
        fprintf(stderr, "No memory available! Bye!\n");
        exit(EXIT_FAILURE);
    }

    /* gather and store information */
    puts("Enter first movie title:");
    while (gets(temp.title) != NULL && temp.title[0] != '\0')
    {
        puts("Enter your rating <0-10>:");
        scanf("%d", &temp.rating);
        while (getchar() != '\n')
            continue;
        if (AddItem(temp, &movies) == false)
        {
            fprintf(stderr, "Problem allocating memory\n");
            break;
        }
        if (ListIsFull(&movies))
        {
            puts("The list is now full.");
            break;
        }
        puts("Enter next movie title (empty line to stop):");
    }

    /* display */
    if (ListIsEmpty(&movies))
        printf("No data entered. ");
    else
    {
        printf("Here is the movie list:\n");
        Traverse(&movies, showmovies);
    }

    printf("Bye!\n");

    EmptyTheList(&movies);  /* optional cleanup in some editions */

    return 0;
}

void showmovies(Item item)
{
    printf("Movie: %s  Rating: %d\n", item.title, item.rating);
}
相关推荐
傻乐u兔10 分钟前
C语言进阶————指针4
c语言·开发语言
历程里程碑13 分钟前
Linux22 文件系统
linux·运维·c语言·开发语言·数据结构·c++·算法
2601_949146537 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
知南x9 小时前
【Ascend C系列课程(高级)】(1) 算子调试+调优
c语言·开发语言
2的n次方_11 小时前
Runtime 执行提交机制:NPU 硬件队列的管理与任务原子化下发
c语言·开发语言
凡人叶枫12 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
凡人叶枫14 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
傻乐u兔14 小时前
C语言进阶————指针3
c语言·开发语言
CodeSheep程序羊16 小时前
拼多多春节加班工资曝光,没几个敢给这个数的。
java·c语言·开发语言·c++·python·程序人生·职场和发展
I'mChloe16 小时前
PTO-ISA 深度解析:PyPTO 范式生成的底层指令集与 NPU 算子执行的硬件映射
c语言·开发语言