【C 指针有害健康】
    Friday, July 15, 2016
    8:15 PM

    |

    | | —- |

    | Tags: #微博 |

    计算机生成了可选文字:
    IT程序猿
    07/11/2016
    【C 指针有害健康】每一盒香烟的包装上都会写『吸烟有害健康』。白酒瓶上也写了『过度饮酒,有害健康』。本文的外包装上写的则是『阅读有害健康』,特别是『甩掉强迫症』那一节,它适合我自己阅读,但不一定适合你。http://t.cn/R4KwZoY(来自: Segmentfault )
    ![计算机生成了可选文字: 本 文 来 自 : se mentfault 版 权 归 届 原 作 者 c 指 针 有 害 健 康 @仃 程 厚 猿 & & 酷 勤 网 制 作 每 一 盒 杳 姻 的 包 装 上 都 会 写 丨 吸 姻 有 害 鯉 康 〗 。 酒 瓶 上 也 写 了 丨 过 度 饮 氵 酉 , 有 害 健 康 〗 。 本 文 的 外 包 装 上 写 的 则 是 丨 阅 读 有 害 健 康 〗 特 别 是 丨 甩 掉 强 迫 症 〗 那 一 节 , 它 适 合 我 自 己 阅 读 , 但 不 一 定 适 合 你 。 黑 暗 的 内 存 很 多 人 对 c 语 言 深 恶 痛 绝 , 仅 仅 是 因 为 c 语 言 迫 使 他 们 在 编 程 中 必 须 手 动 分 配 与 释 放 内 存 , 然 后 通 过 指 针 去 访 问 , 俏 有 不 慎 可 能 就 会 导 致 程 序 运 行 运 行 时 出 现 内 存 或 内 存 越 界 访 问 c 程 序 的 内 存 逋 R 会 发 生 在 程 序 所 的 堆 空 间 内 , 因 为 程 序 R 能 在 堆 空 间 内 动 态 分 配 内 存 。 指 针 、 耒 初 始 化 的 NULL 指 针 以 及 引 的 内 存 空 间 被 释 放 了 的 指 针 , 如 果 这 些 指 针 访 问 内 存 , 很 容 易 就 让 程 序 挂 掉 除 了 堆 空 间 程 序 还 有 个 一 般 而 言 比 较 小 的 栈 空 间 。 这 个 空 间 是 所 有 的 函 数 廿 享 的 , 每 个 函 数 在 运 行 时 会 伸 占 这 个 空 间 。 栈 空 间 的 大 」 、 是 固 定 的 , 它 是 留 给 函 数 的 参 数 与 局 部 变 量 的 。 栈 空 间 有 点 像 宾 馆 , 你 下 后 , 即 使 将 房 间 倡 的 一 团 韉 , 也 不 需 要 你 去 收 拾 它 , 除 非 你 吧 房 间 很 严 重 的 陨 坏 了 一 c 的 黑 话 来 说 , 即 缓 冲 区 溢 出 。 虽 然 导 致 这 些 问 题 出 觋 的 原 因 很 简 单 , 但 是 却 成 为 缺 乏 编 程 素 荠 的 人 唯 以 克 服 的 障 碍 , 被 c 语 言 吓 哭 很 多 次 之 后 , 他 们 叛 逃 到 了 Java 、 C# 以 及 各 种 动 态 类 型 语 言 的 阵 营 , 因 为 这 些 语 言 将 指 针 隐 藏 了 起 来 , 并 提 供 内 存 垃 圾 回 收 ( GC ) 功 能 。 他 们 贏 了 , 他 们 懒 洋 洋 的 躺 在 沙 发 上 , 拿 着 遥 腔 器 指 内 存 , 信 号 偶 尔 中 断 , 内 存 偶 尔 紊 乱 。 ( 内 存 的 动 态 分 配 与 回 收 c 语 言 标 准 库 ( stdlib ) 中 为 堆 空 间 中 的 内 存 分 配 与 回 收 提 与 free 函 数 。 例 如 , 在 下 面 的 代 码 中 , 我 们 从 Ilial 10 c 堆 空 间 中 分 配 了 7 个 字 节 大 -1\ 的 空 间 , 然 后 又 释 放 了 m a 110 c 0 的 f r e e ( 的 i n c 1 u d e 〈 s t d 1 i b . h 〉 v 0 i d p 一 点 都 不 唯 ! 跟 你 去 学 校 图 书 馆 借 了 7 本 书 , 然 后 又 还 回 去 没 什 么 呐 样 。 有 借 有 还 再 借 不 唯 , 过 期 不 还 就 要 罚 款 。 有 谁 因 为 去 图 书 馆 借 几 本 书 就 被 吓 哭 了 的 ? 我 们 也 可 以 向 堆 空 间 借 点 地 方 存 储 某 种 类 型 的 数 据 111 a 110 c 00 : _n 7 ; free(n) int _n 如 果 你 不 知 道 i nt 类 型 的 数 据 需 要 多 大 的 空 间 才 能 装 下 让 c 编 译 器 去 帮 助 你 计 笪 , 即 S i z e 0 f int _n 111 a 110 c ( s i z e 0 f ( i n 0 的 n 7 ; free(n) 策 略 与 机 制 分 离 在 c 语 言 中 有 关 内 存 管 理 的 机 制 已 简 单 到 了 几 乎 无 法 再 简 单 的 程 度 了 , 那 么 为 何 那 么 多 人 都 在 嘲 笑 讥 讽 挖 苦 扁 骂 讠 且 几 c 的 内 存 管 理 呢 如 果 你 略 微 懂 得 一 些 来 自 Unix 的 哲 学 , 可 能 听 说 过 这 么 一 句 话 : 策 略 与 机 制 分 离 。 如 果 没 听 说 过 这 句 话 , 建 议 阅 读 Eric Raymond 写 的 (Unix 编 程 艺 术 》 第 一 章 中 的 I-Jmx 哲 学 部 分 。 与 让 c 提 供 的 内 存 管 理 机 制 , 至 于 你 怎 么 去 川 a 110 c free 使 这 个 机 制 , 那 与 c 没 有 直 接 关 系 。 例 如 , 你 可 以 手 动 使 与 行 “ 来 管 理 内 存 一 一 最 简 单 的 策 略 , 你 也 可 川 a 110 c 以 实 觋 一 种 略 微 复 杂 一 点 的 基 于 引 计 数 的 内 存 管 理 策 略 还 可 以 基 于 Lisp 之 父 John McCarthy 伸 创 的 Mark&Sweep 笪 法 实 觋 一 种 保 守 的 内 存 动 回 收 策 略 , 还 可 以 将 弓 佣 计 数 与 Mark&Sweep 这 呐 种 策 略 结 合 起 来 实 现 内 存 动 回 收 。 总 之 , 这 些 策 略 都 可 以 在 c 的 内 存 管 理 机 制 上 实 现 。 借 助 Boehm GC 库 , 就 可 以 在 c 程 序 中 实 觋 垃 圾 内 存 的 自 动 回 收 i n c 1 u d e 0 吓 s e r 0 h 〉 i n c 1 u d e 〈 s t d i 0 . h 〉 i n c 1 u d e 〈 i n [ 111 a i n 气 0 i 的 { GC._INIT() , [ 0 r ( i n int *p GC._llALLOC(sizeof(int 的 ALLOC_AT0111C(sizeof(int)) . GC_REALLOC ( q , GC_get heap a p S 1 Z e e [ u rn 0 : : 在 C 程 序 中 使 用 B 艹 hm G C 库 , int _q GC Il assert(_p 2 s i z e 0 「 0 (t) ) printf(“He s i z e 0 ) 或 用 GC MALLO C C MALLOC ATOMIC 去 掉 所 有 的 “ 艹 语 旬 。 C MALLOC 会 用 于 存 储 指 针 据 的 堆 空 间 。 1 m a 1 ] 0 c , 然 后 用 于 分 不 ATOMIC 如 果 你 的 系 统 ( Linux ) 中 安 装 了 boehm-gc 库 ( 很 微 型 , 刚 100 多 Kb ) 可 以 gcc 编 译 这 个 程 序 然 后 运 行 一 次 体 验 一 下 , 编 译 命 令 如 下 $ c c 一 1 c t e s t 一 亡 c GNU 的 Scheme 解 释 器 Guile 2.0 就 是 的 boehm-gc 来 实 觋 内 存 回 收 的 。 有 很 多 项 目 在 boehm-gc, 只 不 过 很 少 有 人 听 说 过 它 们 , 见 http://www.hboehm.info/gc/#users 如 果 c 语 言 直 唼 提 供 了 某 种 内 存 管 理 策 略 , 无 论 是 提 供 引 计 数 还 是 Mark&Sweep 抑 或 这 二 者 的 结 合 体 , 那 么 都 是 在 剥 夺 其 他 策 略 生 存 的 机 会 。 例 如 , 在 」 ava 、 C# 以 及 动 态 类 型 语 言 中 , 你 很 唯 再 实 觋 一 种 新 的 内 存 管 理 策 略 了 一 一 例 如 手 动 分 配 与 释 放 这 种 策 略 。 Eric Raymond 说 , 将 策 略 与 机 制 糅 在 一 起 会 导 致 有 叻 个 问 题 , ( 1 ) 策 略 会 变 得 死 板 , 难 以 适 应 F 需 求 的 改 变 ; ( 2 ) 任 何 策 略 的 改 变 都 极 有 可 能 动 机 制 。 相 反 , 如 果 将 二 者 剥 离 , 可 以 在 探 索 新 策 略 的 时 佞 不 会 破 坏 机 制 , 并 且 还 检 验 了 机 制 的 喼 定 性 与 有 效 性 。 Unix 的 哲 学 与 c 有 何 相 干 ? 不 仅 是 有 何 相 干 , 而 且 是 急 急 相 关 ! 因 为 C 与 Umx 是 鸡 生 蛋 & 蛋 生 鸡 的 关 系 一 一 Umx 是 c 语 言 开 发 的 , 而 c 语 言 在 Unix 的 开 发 过 程 中 逐 渐 成 熟 。 c 语 言 R 提 供 机 制 不 提 供 策 略 , 也 正 因 为 如 此 才 招 致 了 那 些 贪 心 的 人 的 鄙 薄 。 这 么 多 年 来 , 像 c 语 言 提 供 的 这 种 “ 11 艹 + free 的 内 存 管 理 机 制 一 直 都 没 有 什 么 变 化 , 而 计 笪 机 科 学 家 们 提 出 的 内 存 管 理 策 略 在 数 量 上 可 能 会 非 常 惊 人 。 像 C++ 11 的 智 能 指 针 与 」 ava 的 GC 技 术 , 如 果 从 研 究 的 角 度 来 看 , 可 能 它 们 已 届 于 陈 旧 的 内 存 回 收 策 略 了 。 因 为 它 们 的 缺 点 早 就 暴 露 了 出 来 , 相 应 的 改 进 方 案 肯 定 不 止 一 种 被 提 了 出 来 , 而 且 其 中 肯 定 会 有 一 些 策 略 是 基 于 概 率 笪 法 的 一 那 些 孜 孜 不 倦 到 处 寻 找 问 题 的 计 笪 机 科 学 家 们 , 怎 能 错 过 这 种 可 以 打 怪 廾 级 赚 的 好 机 会 ? 总 之 , c 已 提 供 了 鯉 全 的 内 存 管 理 机 制 , 它 并 没 有 限 制 你 使 它 实 现 一 种 新 的 内 存 管 理 策 略 。 手 动 管 理 内 存 的 常 见 陷 阱 在 编 写 c 程 序 时 , 手 动 管 理 内 存 R 有 一 个 基 本 原 则 是 谁 需 要 , 谁 分 配 , 谁 最 后 使 , 谁 负 责 释 放 。 这 里 的 丨 谁 〗 指 的 是 函 数 。 也 就 是 说 , 我 们 有 义 务 全 程 跟 踪 某 块 被 分 配 的 堆 空 间 的 生 命 周 期 , 悄 有 忽 可 能 就 会 导 致 内 存 或 内 存 被 重 复 释 放 等 问 题 。 那 些 在 函 数 内 部 作 为 局 部 变 量 使 的 堆 空 间 比 较 容 易 管 理 R 要 在 函 数 结 尾 部 分 悄 微 留 心 将 其 释 放 即 可 一 个 函 数 写 完 后 , 苜 先 检 查 一 下 所 分 配 的 堆 空 间 是 否 被 正 确 释 放 , 这 个 习 愠 很 好 荠 成 。 这 种 简 单 的 事 其 实 根 本 不 劳 烦 那 些 复 杂 的 内 存 回 收 策 略 。 c 程 序 内 存 管 理 的 复 杂 之 处 在 于 在 某 个 函 数 中 分 配 的 堆 空 间 可 能 会 一 路 搌 转 穿 过 七 八 个 函 数 , 最 后 又 忘 记 将 其 释 放 , 或 者 本 来 是 希 望 在 第 7 个 函 数 中 访 问 这 块 堆 空 间 的 , 结 果 却 在 第 3 个 函 数 中 将 其 释 放 了 。 尽 管 这 样 的 场 景 一 般 不 会 出 觋 ( 根 据 快 递 公 司 去 包 的 概 率 , 这 种 堆 空 间 传 递 实 误 的 概 率 大 概 有 0 、 佣 1 ) 但 是 一 出 觋 , 就 够 你 孤 狂 一 回 的 了 。 没 什 么 好 方 法 , 惟 有 提 高 身 修 荠 , 例 如 对 于 在 函 数 中 击 的 太 远 的 堆 空 间 , 一 定 要 警 惕 , 并 且 思 考 是 不 是 设 计 思 路 有 问 题 寻 找 缩 短 堆 空 间 传 罹 路 径 的 有 效 方 法 。 堆 空 间 数 据 在 多 个 函 数 中 传 递 , 这 种 情 兄 往 往 出 觋 于 面 向 对 象 程 范 式 。 例 如 在 C++ 程 序 中 , 对 象 会 作 为 一 种 穿 着 隐 行 衣 的 数 据 一 指 针 的 方 式 穿 过 对 象 的 所 有 方 法 ( 类 [ h i s 的 成 员 函 数 ) , 像 穿 糖 葫 芦 一 样 。 不 过 , 由 于 C++ 类 专 门 为 对 象 生 命 终 结 专 门 设 立 了 析 构 函 数 , 只 要 这 个 析 构 函 数 没 被 触 发 , 那 么 这 个 对 象 在 穿 过 它 的 方 法 时 , 一 般 不 会 出 问 题 。 因 为 tins 指 针 是 隐 藏 的 , 也 没 人 会 神 错 乱 在 对 象 的 某 个 方 法 中 去 真 正 的 陷 阱 往 往 出 觋 在 类 的 继 d e 1 e [ e [ h i s 承 上 。 任 何 一 个 训 练 有 素 的 C++ 编 程 者 都 懂 得 什 么 时 佞 动 虚 析 构 函 数 , 否 则 就 会 陷 入 delete 去 释 放 引 用 了 派 生 类 对 象 的 基 类 指 针 所 导 致 的 内 存 陷 阱 之 中 。 在 面 向 对 象 编 程 范 式 中 , 还 会 出 觋 对 象 之 间 彼 此 引 的 觋 象 。 例 如 , 如 果 对 象 A 引 了 对 象 B , 而 对 象 B 又 引 了 对 象 AO 如 果 这 叻 个 对 象 的 析 构 函 数 都 试 图 将 各 所 引 对 象 钅 肖 毁 , 那 么 程 序 会 直 唼 崩 溃 了 。 如 果 R 是 叻 个 相 邻 的 对 象 的 相 互 引 , 这 也 不 唯 解 决 , 但 是 如 果 A 引 了 B , B 引 了 C 引 了 D , D 引 了 B 和 E , E 引 了 A 然 后 你 可 能 就 凌 乱 了 。 如 果 是 基 于 引 计 数 来 实 觋 内 存 动 回 收 , 遇 到 这 种 对 象 之 间 相 互 引 的 情 况 , 虽 然 那 程 序 不 会 崩 溃 , 但 是 会 出 觋 内 存 , 除 菲 借 助 弱 引 来 打 破 这 种 这 种 引 循 环 , 本 质 上 这 R 是 变 相 的 谁 最 后 使 , 谁 负 责 释 放 。 函 数 式 程 范 式 中 , 内 存 逋 问 题 依 然 很 容 易 出 觋 , 特 别 是 在 递 旧 函 数 中 通 常 需 要 借 助 一 种 很 别 田 的 思 维 将 递 旧 函 数 弄 成 尾 递 旧 形 式 才 能 解 决 这 种 问 题 。 另 外 , 惰 性 计 笪 也 可 能 会 导 致 内 存 。 似 乎 并 没 有 任 何 一 种 编 程 语 言 能 够 真 正 完 美 的 解 决 内 存 问 题 一 一 有 人 说 Rust 能 解 决 , 我 不 是 很 相 信 , 但 是 显 而 见 , 程 序 在 设 计 上 越 低 劣 , 越 容 易 导 致 内 存 错 误 。 似 乎 R 有 通 过 大 量 实 践 , 亡 羊 补 牢 , 塞 翁 失 马 , 卧 薪 尝 胆 , 破 釜 沉 舟 , 久 而 久 之 , 等 你 三 观 正 常 了 不 焦 不 躁 了 , 明 心 见 性 了 , 内 存 错 误 这 种 症 就 会 动 从 你 的 c 代 码 中 氵 肖 实 了 一 好 的 设 计 品 味 , 然 就 是 内 存 友 好 的 。 当 我 们 达 到 这 种 境 界 时 , 可 能 就 不 会 再 介 意 在 c 中 手 动 管 理 内 存 。 让 Valgrind 帮 你 养 成 c 内 存 管 理 的 好 习 惯 Linux 环 境 中 有 一 个 专 门 于 c 程 序 内 存 错 误 测 工 具 —valgrmd , 其 他 操 作 系 统 上 应 该 也 有 类 似 的 工 具 valgrind 能 够 发 觋 程 序 中 大 部 分 内 存 错 误 一 一 程 序 中 使 了 耒 初 始 化 的 内 存 , 使 了 已 释 放 的 内 存 , 内 存 越 界 访 问 内 存 盖 以 及 内 存 等 错 误 。 看 下 面 这 个 来 自 IThe Valgrind Quick Start Guidel 的 小 例 子 v 0 i d f 气 0 i d) { i n c 1 u d e 〈 s t d 1 i b . h 〉 int X m a 凵 0 c 0 0 s i z e of ( i nt 的 i n [ 111 a i n 气 0 i d 〕 { x 自 0 ] return 0 : : 不 唯 发 觋 , Ef 函 数 中 即 存 在 这 内 存 , 又 存 在 着 内 存 越 界 访 问 。 设 这 份 代 码 保 存 在 文 件 中 , 然 valgrind—demo. c 后 使 gcc 编 译 它 $ gec 一 一 00 valgrind—demo. c 一 0 valgrind—demo 为 了 让 valgrind 能 够 更 准 确 的 给 出 程 序 内 存 错 误 信 息 议 打 开 编 译 器 的 调 试 选 项 . 里 , 并 且 禁 止 代 码 优 化 , 即 然 后 valgrind 查 valgrind-demo 程 予 —leak—check—yes ./valgrind—demo $ v a 1 r i n d 纤 果 valgrind 输 出 以 下 信 急 Il e Ill C h e C , a Ill e Ill 0 r y e r r 0 d e [ e C [ 0 Copyright ( 0 2002 一 20 适 , and GNU GPI. , d , by Julian Seward et al. Using Valgrind—3 = 1 0 〔 用 0 = . 凵 . 0 and LibVEX: rerun with —h for copyright inf / val r i n d— d e 111 0 Command: I n val i d wr i [ e 0 f s i z e 4 [ 0 x 4 0 0 5 湖 : f 气 a 1 r i n d— d e m 0 . c : 引 y 0 x 4 0 0 5 5 : 111 a i n 气 a 1 r i n d— d e m 0 . c : 1 0 A d d r e s s 0 x 5 1 d 3 0 0 8 i s 0 b y [ e s a [ [ e r a b 10 国 ‘ 0 「 s i z e 4 0 a 凵 0 c , d at 0x4C29F 巨 0 : IliaIloc ()n /usr/lib64/valgrind/vgpreload_memcheck—a111d64 一 1 i X . S 0 〕 一 d e 111 0 . c : 引 i n [I— d e m 0 . c : 1 0 EAP SIJIIIIARY: e s i n I b ] 0 国 ‘ s b y 0 x 、 1 0 0 5 6 7 : 「 气 a 1 r i n d b y 0 x 、 1 0 0 5 8 5 : 川 a i n 气 a 1 r i n u s e a [ e X i [ : 4 0 b y [ [ 0 [ a 1 h e a p u s a e : 110 c s , 0 f r e e s , 4 0 b y [ e s a 110 c a [ e d 4 0 b y [ e s i n 1 b 10 国 ‘ s a r e d e 「 i n i [ e [ y [ 0 s [ i n 10 s s r e c 0 r d 1 0 「 1 at 0x4C29F 巨 0 : 111 a 110 c ( i n /u s r/ 1 i b 0 4 / val r i n d/ v 〕 r e 10 a d 111 e 111 c h e c k—amd64—linux. so 〕 = 1 0 0 〔 用 = a [ r i n ()— d e 111 0 . c : 引 b y 0 x 4 0 0 5 0 7 : f 气 b y 0 x 4 0 0 5 8 5 : 111 a i n I-FAK 气 a 1 r i n [I— d e 111 0 . c : 1 0 SUMMARY: i n 1 b 10 国 ‘ s i n 0 b 1 0 国 ‘ s s i n 0 b 10 国 ‘ s e s i n 0 b 10 国 ‘ s [ e s i n 0 b 10 国 ‘ s = 1 0 〔 用 0 = d e 「 i n i [ e 1 y 10 s [ : 、 1 0 b y [ e s i n d i r e c [ 1 y 10 s [ : 0 b y [ e s p 0 s s i b 1 y 10 s [ : 0 b y [ e s [ i 11 r e a c h a b 性 : 0 b y [ s up p r e s s e d : 0 b y FOI- COunts 以 生 № 品 “ “ 。 茬 一 处 内 S 凵 卩 I n val i d w r i [ e 0 「 s i z e 4 [ 0 x 4 0 0 5 湖 : f 气 a 1 r i n d— d e 111 0 . c : 引 y 0 x 4 0 0 5 8 5 : 111 a i n 气 a 1 r i n d— d e 111 0 . c : 1 0 A d d r e s s 0 x 5 1 d 3 0 0 8 i s 0 b y [ e s a f [ e r a b 1 0 国 ‘ 0 f s i z e ] 0 a 110 c , d a [ 0 x 4 C 2 9 FE 0 : m a 1 ] 0 c ()n /usr/lib64/valgrind/vgpreloadmemcheck—a111d6 、 1 一 1 i X . S 0 〕 一 d e m 0 . c : 引 i n [I— d e 111 0 . c : ] l) b y 0 x 4 0 0 5 0 7 : f 气 a 1 r i n d b y 0 x 4 0 0 5 8 5 : 111 a i n 气 a 1 r 然 后 valgrind 又 发 觋 在 valgrind-demo 程 序 中 存 在 40 字 节 的 内 存 , 即 4 0 b y [ e s i n 1 b 10 国 ‘ s a r e d e f i n i [ e 1 y 10 s [ i n 10 s s r e c 0 r d 1 0 「 1 = 1 0 0 〔 用 = at 0x4C29F 巨 0 : 111 a 凵 0 c ( i n /u s r/ 1 i b 1 / v a ] r i n d/ v 〕 r e ] 0 a d 111 e 111 c h e c k—amd64—linux. so 〕 a 1 r i n d— d e Ill 0 . c : 引 气 a 1 r i n ()— d e m 0 . c : 凵 ) b y 0 x 4 0 0 5 0 7 : 「 气 b y 0 x 4 0 0 5 8 5 : 111 a i n 由 于 我 们 在 译 时 开 启 了 调 试 选 项 , 所 以 valgrind 也 能 告 诉 我 们 内 存 错 误 发 生 在 具 体 哪 一 行 源 代 码 中 。 除 了 可 于 程 序 内 存 错 误 的 测 之 外 , valgri nd 也 具 有 函 数 调 关 系 跟 踪 、 程 序 缓 冲 区 检 查 、 多 线 程 竟 争 检 测 等 功 能 但 是 无 论 valgrind 有 多 么 强 大 , 你 要 做 的 是 逐 渐 的 脱 它 , 永 远 也 不 要 将 己 的 代 码 建 立 在 丨 反 正 valgrmd 能 帮 我 检 查 错 误 〗 这 样 的 基 础 上 。 甩 掉 强 迫 症 选 降 c 语 言 来 写 程 序 , 这 已 让 我 们 牺 牲 了 很 多 东 西 一 项 目 进 度 、 漂 亮 的 桌 面 程 序 、 炙 手 可 热 的 网 站 前 端 如 果 你 再 为 c 语 言 的 一 些 丨 脆 弱 〗 之 处 患 上 强 迫 症 , 这 样 的 人 生 太 过 于 悲 催 。 c 语 言 就 要 对 自 己 好 一 点 。 负 责 分 配 内 存 的 函 数 可 能 会 遇 到 内 存 分 配 实 败 的 情 川 a 110 c 于 是 , 问 题 就 来 了 , 是 否 需 要 在 况 , 这 时 它 会 返 回 NULL 程 序 中 检 测 的 返 回 值 是 否 为 NULL ? 我 觉 得 没 必 要 川 a 110 c 测 只 需 记 住 可 能 会 返 回 这 一 事 实 即 可 。 如 果 Ilial 10 c NULL 一 个 程 序 连 内 存 空 间 都 无 法 分 配 了 , 那 么 它 还 有 什 么 再 继 续 运 行 的 必 要 ? 有 时 , 可 能 会 因 为 系 统 中 进 程 存 在 内 存 导 致 你 的 程 序 无 法 分 配 内 存 , 这 时 你 使 川 a 110 c 的 NULL 指 针 来 访 问 内 存 , 会 出 觋 地 址 越 界 错 误 , 这 种 错 误 很 容 易 定 位 , 并 且 由 于 你 知 道 可 能 会 返 回 川 a 110 c NULL 事 实 , 也 很 容 易 确 定 错 误 的 原 因 , 实 在 不 济 , 还 有 valgrindo 如 果 确 实 有 对 “ ] 1 “ 返 回 值 进 行 检 查 的 必 要 , 例 如 本 文 评 论 中@依云 所 说 的 那 些 情 兄 , 可 以 者 虑 这 样 做 i n c 1 u d e 〈 s [ d i 0 . h 〉 i n c 1 u d e 〈 s t d 1 i b . h 〉 d e f i n e S AFE MALLOC.(n) safe malloc(n) v 0 i d s a 「 e m a 110 c ( s 0 e [ 市 { mal 10 c ( 市 v 0 i d _p return p: printf(“ 你 的 内 存 不 用 , 我 先 撤 了 ! (“) . “ i 0 一 0 } i n [ Ill a i n 气 0 i d SAFE MALLOC(sizeof(int)) int _p return 0 : : 如 果 你 被 我 说 服 了 , 决 定 不 去 检 查 的 返 回 值 是 否 Ilial 10 c 为 那 么 又 一 个 问 题 随 之 而 来 。 我 们 是 否 需 要 在 程 序 NULL 中 检 测 一 个 指 针 是 否 为 黼 且 ? NIJI 、 L 指 针 实 在 是 太 恐 怖 了 直 接 决 定 了 程 序 的 生 死 。 为 了 安 全 起 见 , 在 一 个 指 针 时 测 一 下 它 的 值 是 否 为 NIJI 、 L 似 乎 非 常 有 必 要 。 特 别 是 向 一 个 函 数 传 递 指 针 , 很 多 程 专 家 都 建 议 在 函 数 内 部 苜 先 要 测 指 针 参 数 是 否 为 并 将 这 种 行 为 取 名 为 丨 契 约 式 NULL 程 〗 。 之 所 以 是 契 约 式 的 , 是 因 为 这 种 检 测 已 假 设 了 函 数 的 调 者 可 能 会 传 入 NIJI 、 [ 事 实 上 这 种 契 约 非 常 容 易 被 破 坏 , 例 如 《 0 i d f 0 0 ( i n [ _p 〕 { p r i n [ 「 下 Y 0 u p a s s e d a NIJI- L p 0 i nt e r ! n 0 i n [ 111 a i n 气 0 i d 〕 { int _p return 0 : : 当 我 将 一 个 耒 初 始 化 的 指 针 传 给 数 的 检 测 不 会 起 到 任 何 作 。 函 数 时 foo 函 数 对 参 可 能 你 会 辩 解 , 说 调 foo 函 数 的 人 , 应 该 先 将 p 指 针 初 始 化 为 但 这 有 些 欺 欺 人 。 契 约 应 当 是 双 方 彼 此 达 成 NULL 一 致 意 见 之 后 才 能 签 署 , 而 不 是 你 单 方 面 起 草 一 个 契 约 , 然 后 要 求 他 人 必 须 趕 守 这 个 契 约 。 foo 不 应 该 为 F 传 入 无 效 的 指 针 而 买 单 , 何 况 它 也 根 本 无 法 买 这 个 单 一 一 你 能 检 测 的 但 是 无 法 检 测 耒 初 始 化 的 指 针 或 者 被 释 放 了 的 指 了 NULL 针 。 也 许 你 认 为 R 要 坚 時 将 指 针 初 妒 化 为 且 并 坚 時 消 除 野 指 针 , 那 么 艹 中 的 NULL 检 测 就 是 有 效 的 。 但 是 很 可 惜 , 野 指 针 不 是 那 么 容 易 消 除 , 下 面 就 会 讨 论 此 事 。 且 是 不 能 彻 底 氵 肖 除 的 问 题 , 就 不 应 该 再 浪 心 机 , 否 则 R 是 将 一 问 题 演 变 了 另 一 个 问 题 而 已 。 那 些 被 重 重 遮 腌 的 问 题 , 一 被 触 发 , 你 会 更 看 唯 看 真 相 指 针 不 应 该 受 到 不 公 正 待 遇 。 如 果 你 处 处 纠 结 程 序 中 到 的 整 型 数 或 浮 点 数 是 否 会 溢 出 , 或 者 你 击 在 人 家 楼 下 也 不 是 时 时 仰 望 上 方 有 没 有 高 空 坠 物 , 那 么 也 就 不 应 该 对 指 针 是 否 为 NULL 那 么 重 视 , 县 至 不 惜 代 价 为 其 修 建 万 里 长 城 。 在 c 言 中 不 需 要 指 针 的 且 契 约 , R 需 要 溧 守 指 针 法 律 你 要 传 给 我 指 针 , 就 必 须 保 证 你 的 指 针 是 有 戏 的 , 否 则 我 就 程 序 崩 溃 来 惩 罚 你 。 第 = 个 问 题 依 然 与 N 肚 L 有 关 , 那 就 是 一 个 指 针 所 引 的 内 存 空 间 被 释 放 后 , 是 否 要 将 这 个 指 针 賦 值 为 NULL ? 对 于 这 个 门 题 , 大 家 一 致 认 为 应 该 为 之 賦 以 黼 且 否 则 这 个 指 针 就 成 为 丨 野 指 针 〗 一 一 野 指 针 是 有 害 的 。 一 开 始 我 也 这 么 认 为 , 但 是 久 而 久 之 觉 得 氵 肖 除 野 指 针 , 是 一 种 很 无 聊 的 行 为 。 程 序 中 之 所 以 会 出 觋 野 指 针 引 发 的 内 存 错 误 往 往 意 味 着 你 的 代 码 出 觋 了 拙 劣 的 设 计 《 如 果 消 除 野 指 针 , 再 配 合 指 针 是 否 为 且 的 检 测 , 这 样 做 固 然 可 以 很 快 的 定 位 出 错 点 , 但 是 换 来 的 常 是 一 个 很 脏 的 补 丁 式 修 正 可 能 会 继 续 得 到 纵 容 。 如 果 你 真 的 害 怕 野 指 针 , 可 以 像 下 面 这 样 做 訁 i n c 1 u d e 〈 s [ d i 0 . h 〉 i n c 1 u d e 〈 s [ 旧 i b . h 〉 A 陣 一 ( 的 safe_free((void _ 00 的 的 而 坏 的 设 计 d e 0 n e S V 0 i d S a f e 「 r e e 气 0 i d _p 〕 { ree(_p) . NULL. p r i nt f 下 哎 呀 , 我 怕 死 野 指 针 了 i n [ 111 a i n 气 0 i d 〕 { int *p mal 10 c ( s i z “ 0 i n 0 〕 eturn 0 ; : f 0 r ( i n i SAF 巨 一 F 胃 刂 《 伟 ) 对 于 所 弓 佣 的 内 存 被 释 放 了 的 指 针 , 即 使 賦 之 以 NULL , 也 R 能 解 决 那 些 你 原 本 一 眼 能 看 出 来 的 问 题 。 更 韉 糕 的 是 当 你 对 氵 肖 除 野 指 针 非 常 上 心 时 , 每 当 消 除 一 个 野 指 针 , 可 能 会 让 你 觉 得 你 的 程 序 更 加 鯉 壮 了 , 这 种 错 觉 反 而 消 除 了 你 的 警 惕 之 心 。 如 果 一 块 内 存 空 间 被 多 个 指 针 弓 佣 , 当 你 通 过 其 中 一 个 指 针 释 放 这 块 内 存 空 间 之 后 , 并 賦 该 指 针 以 NULL 那 么 其 他 几 个 指 针 该 怎 么 处 理 ? 也 许 你 会 说 , 那 应 该 引 计 数 技 术 来 解 决 这 样 的 问 题 。 弓 佣 计 数 的 确 可 以 解 决 一 些 问 题 , 但 是 它 又 带 来 一 个 新 的 问 题 , 对 于 指 针 所 引 的 空 间 在 引 计 数 为 0 时 , 它 被 释 放 了 , 这 时 另 外 一 个 地 方 依 然 有 代 码 在 试 图 这 时 该 怎 么 处 理 ? 绝 对 的 不 去 测 指 针 是 否 为 肯 定 也 不 科 学 。 因 为 有 NULL 时 ULL 是 作 为 状 态 来 的 。 例 如 在 树 结 构 中 可 以 根 据 任 一 结 点 中 的 子 结 点 指 针 是 否 为 NULL 来 判 断 这 个 结 点 是 否 为 叶 结 点 。 有 些 函 数 通 过 返 回 告 诉 调 者 丨 我 可 耻 的 NULL 失 败 了 〗 。 我 觉 得 这 才 是 1.1. 真 正 的 武 之 地 。 王 垠 在 丨 程 的 智 慧 〗 一 文 中 告 诫 大 家 , 尽 量 不 要 让 函 数 返 回 NULL , 他 认 为 如 果 你 的 函 数 要 返 回 丨 没 有 〗 或 丨 出 错 了 〗 之 类 的 结 果 , 尽 量 使 Java 的 异 常 机 制 。 这 种 观 点 也 许 是 对 的 , 但 是 鉴 于 c 没 有 异 常 机 制 ( 在 c 中 可 以 set 」 mp / ng 」 mp 勉 强 忄 莫 拟 异 常 ) , 口 有 NULL 可 馬。 有 些 人 形 而 上 学 强 加 附 会 的 将 这 种 观 点 解 读 为 让 函 数 返 囗 是 有 害 的 , 县 至 将 这 种 行 为 视 为 丨 低 级 错 误 〗 县 至 认 为 c 指 针 的 存 在 本 身 就 是 错 误 , 认 为 这 样 做 是 整 个 软 件 行 业 40 多 年 的 耻 辱 , 这 是 小 题 大 作 , 或 者 说 他 R 有 能 力 将 罪 责 惟 给 NULL 而 没 有 能 力 眼 制 且 的 副 作 如 果 我 们 R 将 且 于 表 亍 丨 没 有 〗 或 丨 出 错 了 〗 的 状 态 , 这 非 但 无 害 , 而 且 会 让 代 码 更 加 简 ; 吉 晰 。 如 果 你 期 望 一 个 函 数 能 够 返 回 一 个 有 效 的 指 针 , 那 么 你 就 有 义 务 检 吉 它 是 不 是 真 的 返 回 了 有 效 的 指 针 , 否 则 就 没 必 要 检 查 。 这 种 检 查 其 实 与 这 个 函 数 是 否 有 可 能 返 回 且 无 关 。 类 似 的 NI 且 检 查 , 在 生 活 中 很 常 见 。 即 使 行 的 ATM 机 已 在 安 全 性 上 做 了 重 重 防 , 但 是 你 取 钱 时 , 也 常 会 查 一 下 ATM 吐 出 来 钱 在 数 目 上 对 不 对 。 你 过 马 路 时 , 虽 然 有 红 绿 灯 , 而 且 司 机 师 傅 也 都 是 通 过 骘 照 考 试 的 , 但 你 依 然 会 有 意 识 的 环 顾 左 右 , 看 有 没 有 正 在 过 往 的 车 辆 。 如 果 你 通 过 一 个 查 询 函 数 在 c 式 的 泛 型 容 器 中 查 询 一 个 元 素 ( 其 实 是 指 针 ) , 而 容 器 中 没 有 这 个 元 素 , 那 么 查 询 函 数 这 是 一 个 无 效 的 指 针 , 这 时 , 你 可 以 认 为 回 一 《 NULL 吉 询 函 数 内 部 出 错 了 , 也 可 以 认 为 吉 询 函 数 告 诉 你 容 器 中 没 有 这 个 元 素 。 这 种 情 兄 下 , 查 询 函 数 的 返 回 结 果 出 觋 了 二 义 性 , 但 是 这 难 道 不 可 以 视 为 是 重 新 检 吉 询 函 数 正 确 性 的 好 机 会 么 ? 你 可 以 行 遍 历 你 所 的 容 器 中 是 否 存 在 要 查 询 的 元 素 , 如 果 确 定 有 , 那 么 可 以 肯 定 是 刚 才 你 的 吉 询 函 数 有 bugo 如 果 容 器 中 的 确 没 有 这 个 元 素 , 那 么 查 询 函 数 的 正 确 性 就 得 到 了 证 , 同 时 你 应 该 反 思 , 为 什 么 你 的 代 码 要 去 查 询 一 个 根 本 就 不 在 容 器 中 的 元 素 ! 如 果 你 坚 時 NULL 的 意 又 不 明 确 而 导 致 歧 义 , 然 后 得 出 睢 论 丨 返 回 的 函 数 是 NULL 有 害 的 〗 , 那 么 马 克 思 都 会 比 你 善 于 写 程 序 。 当 你 打 笪 测 一 个 指 针 的 值 是 否 为 N 肚 L 时 , 问 题 又 来 了 、 我 们 是 应 该 = NI 旧 0 { 还 是 应 该 很 多 人 害 怕 出 错 , 他 们 往 往 会 选 降 第 一 种 判 断 方 式 , 他 们 的 理 由 是 在 某 些 c 的 实 觋 ( 编 译 器 与 标 准 库 ) 中 NULL 值 可 能 不 是 这 个 理 由 也 许 对 于 C99 之 前 的 C 是 成 立 的 , 但 是 至 少 从 C99 就 不 再 是 这 样 了 。 C99 标 准 的 6 、 3 、 2 、 3 节 , 明 确 将 空 指 针 定 义 为 常 量 0 在 觋 代 一 些 的 c 编 译 器 上 , 完 全 可 以 放 心 使 更 为 简 咭 且 直 观 的 第 二 种 判 断 方 式 。 c 语 言 就 不 要 想 太 多 。 想 的 太 多 , 你 可 能 就 不 会 或 者 不 敢 编 程 了 。 c 语 言 , 你 又 必 须 想 太 多 , 因 为 不 安 全 的 因 素 到 处 都 有 , 但 是 也 R 有 不 安 全 的 东 西 才 真 正 是 有 威 力 的 工 具 , 刀 枪 剑 戟 , 车 包 刂 磨 , 布 鲁 弗 莱 学 院 传 授 的 挖 机 技 术 , 哪 样 不 能 要 人 命 ! 不 要 想 太 多 , 指 的 是 不 要 在 一 些 细 忮 耒 节 之 处 去 考 虑 安 全 性 , 县 至 对 于 野 指 针 这 种 午 西 都 诚 惶 诚 恐 。 必 须 想 太 多 , 指 的 是 多 从 程 序 的 逻 辑 层 面 来 考 虑 安 全 性 。 出 错 不 可 1 臼 , 可 1 臼 的 是 你 努 力 一 些 小 技 俩 来 擗 错 误 , 这 种 行 为 R 会 导 致 错 误 向 后 延 迟 , 延 迟 到 基 于 引 计 数 的 内 存 回 收 , 延 迟 到 Java 式 的 GC , 延 迟 到 你 认 为 可 以 高 枕 无 忧 然 而 错 误 却 像 腐 症 般 的 出 觋 的 时 佞 。 不 好 的 设 计 品 味 上 文 谈 到 , 内 存 错 误 往 往 是 由 不 良 的 设 计 导 致 的 。 我 不 确 定 怎 样 的 设 计 笪 是 好 品 味 的 , 但 是 我 可 以 确 定 一 些 品 味 不 怎 么 样 的 设 计 第 一 种 品 味 不 怎 么 样 的 设 计 是 割 裂 笪 法 与 数 据 结 构 的 关 系 。 这 种 设 计 源 于 对 教 科 的 盲 目 信 仰 。 几 乎 任 何 一 本 讲 数 据 结 构 与 笪 法 的 书 都 会 煞 有 介 事 的 告 诉 你 程 序 : 据 结 构 + 算 法 。 这 个 公 式 〗 是 Pascal 之 父 Nicklaus Wirth 提 出 的 , 但 实 际 上 十 同 废 话 , 类 似 于 英 语 : 单 词 + 语 法 。 可 是 这 种 废 话 却 让 许 多 人 形 而 上 学 了 。 有 些 人 坚 定 不 移 的 确 信 R 要 吧 数 据 结 构 设 计 正 确 了 正 确 的 笪 法 不 言 明 , 于 是 他 们 从 面 向 对 象 开 始 设 计 程 序 。 还 有 些 人 坚 定 不 移 的 确 信 R 要 将 笪 法 设 计 正 确 了 正 确 的 数 据 结 构 不 言 明 , 于 是 他 们 就 从 笪 法 设 计 开 始 。 这 都 是 不 学 习 马 克 思 哲 学 的 下 场 。 马 克 思 哲 学 是 一 门 注 重 迭 代 的 哲 学 , 马 克 思 常 说 , 笪 法 与 数 据 结 构 是 矛 盾 的 , 二 者 统 一 于 程 序 之 中 , 笪 法 决 定 了 数 据 结 构 , 数 据 结 构 又 反 过 来 影 响 笪 法 。 马 克 思 说 的 肯 定 不 是 废 话 , 任 何 一 个 有 素 荠 的 程 序 员 都 不 会 否 定 迭 代 设 计 。 任 何 一 个 程 序 在 诞 生 之 初 都 不 是 完 美 的 , 但 是 负 责 任 的 设 计 者 会 努 力 使 之 进 化 , 趋 向 完 美 如 果 马 克 思 学 程 , 他 一 定 会 将 泛 型 程 与 面 向 对 象 程 这 叻 大 范 式 统 一 起 来 , 左 手 画 圆 , 右 手 画 方 , 傲 视 群 雄 。 达 尔 文 也 说 过 , 程 序 不 是 设 计 出 来 的 而 是 进 化 出 来 的 。 第 二 种 品 味 不 怎 么 样 的 设 计 是 面 向 某 种 编 程 范 式 。 我 在 丨 面 向 指 针 程 〗 一 文 中 捏 造 了 一 个 很 简 单 的 例 子 , 然 后 将 面 向 对 象 、 泛 型 程 以 及 函 数 式 程 中 最 基 本 的 手 段 穿 届 在 一 起 , 结 果 可 以 得 到 一 个 思 路 晰 、 代 码 简 ; 吉 的 」 、 程 序 。 其 实 这 个 例 子 源 很 多 年 前 我 己 写 的 一 个 双 向 链 表 忄 莫 块 , 在 c 构 建 悄 微 有 点 馍 的 程 序 或 库 时 , 这 些 手 段 都 是 最 基 本 的 。 事 实 上 , 当 时 我 在 写 这 些 代 码 时 , 并 不 怎 么 懂 面 向 对 象 、 泛 型 编 程 以 及 函 数 式 程 这 些 烧 脑 的 概 念 , 完 全 是 为 了 解 决 我 面 对 的 一 些 」 、 问 题 , 然 而 然 的 上 了 这 些 手 段 。 很 多 年 后 我 才 隐 约 发 觋 这 些 手 段 竟 然 对 应 着 一 种 又 一 种 程 范 式 的 推 形 。 我 应 该 庆 幸 , 除 了 指 针 与 宏 之 外 没 有 任 何 特 性 的 c 语 言 没 有 给 我 带 来 太 多 唯 以 理 解 的 概 念 , 以 至 于 我 可 以 直 唼 面 向 问 题 编 程 C 语 言 的 发 明 者 Dannis Ritche 说 , A language that doesn’t have everything is actually easier to programin thansome thatdo 翻 译 过 来 , 是 丨 不 试 图 有 一 切 的 语 言 实 厅 上 要 比 那 些 试 图 有 一 切 的 语 言 更 易 于 编 程 〗 大 部 分 情 况 下 , 我 们 写 的 代 码 在 逻 辑 上 并 不 复 杂 , 所 以 各 种 编 程 范 式 看 上 去 都 同 样 有 效 一 一 如 果 你 说 你 能 面 向 对 象 解 决 问 题 , 那 么 肯 定 会 有 人 说 他 函 数 式 编 程 也 能 解 决 同 样 的 问 题 。 大 部 分 程 序 在 数 据 结 构 与 笪 法 方 面 R 到 了 线 性 表 与 排 序 笪 法 , 程 序 中 大 部 分 代 码 是 与 问 题 领 域 息 息 相 关 的 。 像 树 与 图 这 种 数 据 结 构 及 相 关 的 笪 法 , 往 往 已 以 库 的 形 式 被 实 觋 了 。 就 连 遗 传 笪 法 、 神 网 络 笪 法 以 及 支 時 向 量 机 这 些 复 杂 的 笪 法 也 有 觋 成 的 库 可 调 当 问 题 足 够 复 杂 时 , 你 会 发 觋 任 何 程 语 言 、 范 式 以 及 框 架 都 没 法 帮 助 你 解 决 问 题 , 它 们 县 至 对 你 如 何 理 解 问 题 都 没 有 任 何 帮 助 。 在 我 看 来 , 任 何 程 范 式 在 本 质 上 都 是 代 码 层 面 的 丨 图 十 界 面 ( GUI ) 〗 , 它 们 并 不 能 真 正 代 表 设 计 上 的 好 品 味 。 如 果 你 的 程 序 是 恃 续 进 化 的 , 那 么 它 总 是 有 可 能 进 化 为 最 适 合 它 的 那 些 程 范 式 。 如 果 莱 布 尼 茨 、 欧 拉 、 马 等 大 神 改 行 写 程 序 , 他 们 一 定 能 写 出 具 有 最 」 、 作 量 的 程 序 , 而 不 是 青 负 一 大 堆 编 程 范 式 所 带 来 的 各 种 包 袱 的 程 序 。 第 三 种 品 味 不 怎 么 样 的 设 计 是 不 为 己 的 设 计 提 供 有 效 的 文 裆 , 主 要 表 觋 为 ( 1 ) 文 档 写 的 比 代 码 还 烂 ; ( 2 ) 文 裆 不 能 反 映 最 新 的 代 码 ; ( 引 干 脆 不 写 文 裆 , 让 他 人 去 read the fucking source code 、 如 果 你 能 够 长 期 维 沪 你 所 写 的 代 码 , 不 提 供 有 效 的 文 档 也 不 是 什 么 大 事 , 否 则 你 让 别 人 去 阅 读 你 写 的 fucking source code , 那 是 对 他 人 的 侮 辱 。 因 为 你 是 面 向 机 器 写 代 码 , 他 人 要 想 读 懂 你 的 代 码 , 必 须 通 过 代 码 去 逆 向 还 原 你 的 思 路 。 一 些 水 平 很 烂 的 的 程 序 员 , 企 图 像 Linus 那 样 高 调 趾 高 气 扬 的 让 我 们 去 阅 读 他 们 写 的 代 码 , 这 种 行 为 无 异 于 让 我 们 从 其 排 物 中 测 他 们 中 午 在 哪 个 馆 子 吃 了 什 么 饭 一 结 果 往 往 是 他 们 的 代 码 很 快 就 死 掉 了 。 这 个 世 界 上 能 实 觋 代 码 即 文 裆 , 文 档 即 代 码 的 人 几 乎 没 有 。 即 使 软 件 世 界 的 泰 山 北 斗 Donald Knuth 老 先 生 也 得 借 助 文 式 程 的 方 式 来 注 解 己 的 代 码 , 也 就 是 说 他 R 能 达 到 又 能 写 又 能 写 代 码 的 境 界 , 即 便 如 此 , 这 个 星 球 上 能 与 之 比 肩 的 人 寥 寥 无 几 。 我 又 成 功 的 跑 题 了 。 其 实 我 想 说 的 是 , 与 这 些 品 味 不 好 的 设 计 相 比 c 管 理 一 下 内 存 所 带 来 的 繁 琐 与 困 难 根 本 不 值 一 提 。 请 记 住 Peter Norvig 说 的 学 会 编 程 通 常 需 要 十 年 , 为 何 人 人 都 这 么 着 急 ? 来 自 : http://t.cn/R4cMF04
    查看源微博
    已使用 Microsoft OneNote 2016 创建。