C++ 程 序 设 计 课 程 简 介 课 程 沿 革 课 程 要 求 课 程 内 容 教 学 内 容 讲 课 学 时 上 机 学 时 计 算 机 基 础 知 识 4 C++ 入 门 与 基 本 数 据 类 型 4 表 达 式 和 语 句 6 4 函 数 和 程 序 结 构 8 4 数 组 和 结 构 6 4 指 针 和 引 用 8 面 向 对 象 程 序 设 计 3 类 与 构 造 函 数 8 4 堆 与 拷 贝 构 造 函 数 2 继 承 4 4 I/O 流 3 4 合 计 56 24 第 1 章 计 算 机 基 础 知 识 1.1 计 算 机 的 基 本 组 成 1.1.1 计 算 机 硬 件 计 算 机 的 发 展 已 经 到 了 第 四 代, 但 其 结 构 仍 然 是 存 储 程 序 式 计 算 机, 又 称 冯. 诺 依 曼 式 计 算 机 它 一 般 由 控 制 器 运 算 器 存 储 器 输 入 和 输 出 设 备 等 五 大 部 分 组 成 输 入 设 备 程 序 和 数 据 输 出 设 备 结 果 存 储 器 取 指 令 取 数 存 数 运 算 器 图 1-1 控 制 器 数 据 线 控 制 线 存 储 器 : 用 来 存 储 程 序 和 数 据 ( 又 分 : 高 速 缓 存 主 存 ( 内 存 ) 辅 助 存 储 器 ( 外 存 ) 及 海 量 存 储 器 ( 磁 带 光 盘 ) 等 ) 运 算 器 : 用 来 执 行 规 定 的 运 算 CPU 控 制 器 : 指 挥 各 部 件 按 程 序 要 求 实 现 自 动 操 作 输 入 / 输 出 设 备 : 用 于 输 入 原 始 数 据 和 输 出 运 算 结 果 1.1.2 计 算 机 软 件 即 计 算 机 中 的 程 序 数 据 及 有 关 文 档 的 集 合 系 统 软 件 : 直 接 控 制 和 协 调 计 算 机 硬 件, 其 它 软 件 均 通 过 它 发 挥 作 用 的 一 类 软 件 如 操 作 系 统 编 译 程 序 等 应 用 软 件 : 在 特 定 应 用 领 域, 解 决 用 户 具 体 问 题 的 软 件 如 各 种 管 理 信 息 系 统 财 务 软 件 等 1.1.3 关 于 地 址 文 件 路 径
1.2 关 于 二 进 制 1.2.1 什 么 是 二 进 制 我 们 日 常 所 用 的 计 数 制 是 十 进 制, 即 逢 十 进 一, 每 一 位 的 基 数 是 十 的 若 干 次 幂, 如 1980=1 10 3 +9 10 2 +8 10 1 +0 10 0 所 谓 二 进 制 与 之 类 似, 但 它 是 逢 二 进 一, 每 一 位 的 基 数 是 二 的 若 干 次 幂, 如 (11010) 2 =1 2 4 +1 2 3 +0 2 2 +1 2 1 +0 2 0 =(26) 10 1.2.2 计 算 机 中 为 什 么 要 使 用 二 进 制 因 为 数 字 在 计 算 机 中 是 以 电 子 器 件 的 物 理 状 态 来 表 示 的, 二 进 制 只 需 0 和 1 两 个 数 字 符 号, 可 以 用 电 子 器 件 的 低 电 平 和 高 电 平 两 种 不 同 的 状 态 来 表 示 其 运 算 电 路 容 易 实 现 且 运 行 可 靠 而 要 制 造 出 具 有 10 种 稳 定 状 态 的 电 子 器 件 来 表 示 十 进 制 中 的 10 个 数 字 符 号 是 非 常 困 难 的 1.2.3 二 进 制 与 十 进 制 的 相 互 转 换 采 用 除 2 取 余 法 将 十 进 制 整 数 转 换 成 二 进 制 整 数 ; 采 用 乘 2 取 整 法 将 十 进 制 小 数 转 换 为 二 进 制 小 数 例 如 十 进 制 数 39: 例 如 十 进 制 小 数 0.25: 2 39 2 19 2 9 2 4 2 2 2 1 0 余 数 为 1, 即 a 0 =1 余 数 为 1, 即 a 1 =1 余 数 为 1, 即 a 2 =1 余 数 为 0, 即 a 3 =0 余 数 为 0, 即 a 4 =0 余 数 为 1, 即 a 5 =1 商 为 0, 结 束 0.25 2 0.5 2 1.0 0.0 整 数 部 分 为 0, 即 a -1 =0 整 数 部 分 为 1, 即 a -2 =1 余 下 的 小 数 部 分 为 0, 结 束 结 果 为 (39) 10 = (a 5 a 4 a 3 a 2 a 1 a 0 ) 2 = (100111) 2 结 果 为 (0.25) 10 = (0.a -1 a -2 ) 2 = (0.01) 2 对 一 般 十 进 制 数, 将 整 数 部 分 与 小 数 部 分 分 别 转 换, 然 后 再 组 合 起 来 例 如 : (39.25) 10 = (100111.01) 2 采 用 按 幂 次 展 开 的 方 法 即 可 将 二 进 制 数 转 换 为 十 进 制 数 例 如 : (100111.01) 2 =1 2 5 +0 2 4 +0 2 3 +1 2 2 +1 2 1 +1 2 0 + 0 2-1 +1 2-2 = (39.25) 10 1.2.4 八 进 制 十 六 进 制 及 其 与 二 进 制 的 相 互 转 换 由 于 二 进 制 书 写 复 杂, 不 易 读, 而 八 进 制 和 十 六 进 制 与 二 进 制 有 着 很 简 单 的 对 应 关 系, 且 书 写 较 简 单, 所 以 常 用 它 们 表 示 八 进 制 : 逢 八 进 一,0,1,2,3,4,5,6,7 十 六 进 制 : 逢 十 六 进 一,0,1,2,3,4,5,6,7,8,9, A,B,C,D,E,F 与 十 进 制 之 间 的 相 互 转 换 与 二 进 制 类 似 与 二 进 制 之 间 的 相 互 转 换 : (1) 八 进 制 到 二 进 制 : 因 为 8=2 3, 所 以 将 每 位 八 进 制 数 用 相 应 的 三 位 二 进 制 数 代 替 即 可, 例 如 (15.2) 8 = (001101.010) 2 = (1101.01) 2 (2) 十 六 进 制 到 二 进 制 : 因 为 16=2 4, 所 以 将 每 位 十 六 进 制 数 用 相 应 的 四 位 二 进 制 数 代 替 即 可, 例 如 (2B1) 16 = (001010110001) 2
(3) 二 进 制 到 八 进 制 : 从 个 位 起 每 三 位 二 进 制 数 转 换 为 一 位 八 进 制 数 即 可, 如 最 后 一 组 不 足 三 位 时, 添 0 补 足 三 位 例 如 : (1101.01) 2 = (15.2) 8 (4) 二 进 制 到 十 六 进 制 : 从 个 位 起 每 四 位 二 进 制 数 转 换 为 一 位 十 六 进 制 数 即 可, 如 最 后 一 组 不 足 四 位 时, 添 0 补 足 四 位 例 如 : (1101.01) 2 = (D.4) 16 1.3 各 种 信 息 在 计 算 机 内 部 的 表 示 方 法 信 息 编 码 1.3.1 字 符 编 码 除 数 字 外, 各 种 字 符, 包 括 汉 字, 在 计 算 机 中 也 都 是 用 二 进 制 表 示 的, 为 便 于 处 理, 必 须 为 字 符 汉 字 等 建 立 统 一 的 编 码 标 准 8 个 二 进 制 位 为 一 个 字 节,1024 个 字 节 为 1KB,1024KB 为 1MB 字 符 :ASCII 码, 每 个 字 符 用 一 个 字 节 表 示 有 一 个 码 值 汉 字 : 国 标 码,BIG5 码 等, 一 个 汉 字 用 2 个 字 节 表 示 1.3.2 数 字 编 码 数 字 在 计 算 机 内 部 用 1~10 个 字 节 表 示 原 码 : 用 除 2 取 余 法 得 到 的 二 进 制 数, 称 该 数 字 的 原 码 反 码 : 将 原 码 按 位 取 反, 得 到 的 就 是 该 数 字 的 反 码 补 码 : 正 数 的 补 码 = 原 码 ; 负 数 的 补 码 = 反 码 加 1 在 计 算 机 内 部, 任 何 数 字 均 用 其 补 码 表 示 例 : 假 如 用 1 个 字 节 表 示 数 字, 则 12 在 计 算 机 内 部 的 编 码 为 00001100 而 -12 在 计 算 机 内 部 的 编 码 为 11110100 最 高 位 ( 红 色 ) 就 称 为 符 号 位 1.4 计 算 机 语 言 沟 通 人 和 计 算 机 的 桥 梁 机 器 语 言 : 计 算 机 直 接 能 懂 的 二 进 制 形 式 的 语 言 汇 编 语 言 : 采 用 助 记 符, 与 机 器 指 令 一 一 对 应, 需 要 汇 编 程 序 高 级 语 言 : 类 自 然 语 言 风 格, 易 学 易 记, 需 要 编 译 程 序 C 与 C++: 高 级 语 言,C++ 是 C 的 超 集 见 P3 2.1 C 语 言 的 由 来 和 发 展 第 2 章 C 语 言 概 述 C 语 言 的 开 发 史 源 于 高 级 语 言 和 UNIX 操 作 系 统 的 发 展 要 求 早 期 的 系 统 程 序 设 计, 使 用 的 是 汇 编 语 言, 其 优 点 : (1) 能 体 现 计 算 机 硬 件 指 令 级 的 特 性, 表 达 能 力 强 ; (2) 运 行 效 率 高 其 缺 点 : 可 读 性, 可 移 植 性 及 描 述 问 题 的 性 能 不 如 高 级 语 言 这 样 很 自 然 有 如 下 想 法 : 能 否 用 具 有 足 够 表 达 能 力 的 高 级 语 言 来 进 行 系 统 软 件 的 设 计 呢?Bell 实 验 室 做 了 这 一 尝 试 1970: 在 PDP-11/20 机 上 实 现 了 B 语 言, 并 用 它 编 写 了 UNIX 系 统 的 实 用 程 序 B<---BCPL<---CPL<---ALGOL 60 1969 1960
在 B 语 言 基 础 上, 改 进 其 缺 陷, 发 展 出 了 C 语 言, 其 设 计 目 标 : (1) 保 持 BCPL 和 B 的 精 练 性 及 接 近 硬 件 的 特 点 (2) 恢 复 这 些 语 言 失 去 的 通 用 性 1972: 第 一 个 C 编 译 投 入 使 用 1973:UNIX 用 C 改 写, 加 入 多 道 程 序 功 能, 发 生 质 变 现 在,UNIX 已 得 到 广 泛 推 广, 成 为 公 认 的 第 一 标 准 的 操 作 系 统, 随 着 UNIX 的 进 一 步 开 发,C 也 交 织 在 一 起 被 迅 速 推 广 1983: 对 C 扩 充, 发 展 为 C++ 经 过 不 断 完 善, 现 仍 在 发 展 中 2.2 C 语 言 主 要 特 点 简 洁 紧 凑 使 用 方 便 灵 活 运 算 符 丰 富 数 据 结 构 丰 富 支 持 结 构 化 程 序 设 计 语 法 限 制 不 太 严 格, 编 程 自 由 度 大 允 许 直 接 访 问 物 理 地 址, 接 近 底 层 目 标 代 码 质 量 高, 程 序 执 行 效 率 高 可 移 植 性 好 C++ 语 言 包 括 了 C 的 所 有 特 征 属 性 和 优 点, 同 时 改 进 了 C 的 一 些 不 足, 并 且 支 持 面 向 对 象 的 程 序 设 计 第 3 章 C 语 言 程 序 简 介 3.1 C 语 言 程 序 例 (1) 显 示 字 符 串 最 简 单 的 C 程 序 p7 说 明 了 :(1) 注 解 (2)main 函 数 (3) 语 句 括 号 { (2) 输 入 两 个 整 数, 计 算 一 个 表 达 式 的 值 p8 说 明 了 :(1) 变 量 说 明 (2) 输 入 cin (3) 计 算 表 达 式 (4) 输 出 结 果 (3) 求 两 个 数 中 较 大 者 的 平 方 根, 稍 复 杂 些 p9 说 明 了 :(1) 流 程 控 制,if 语 句 (2)C 程 序 结 构, 例 中 有 一 函 数 max(x,y), 负 责 求 x,y 的 最 大 值 ( 注 意 参 数 说 明 ) 由 以 上 几 例 可 以 看 出 : (1)C 的 基 本 程 序 单 位 是 函 数 : 每 个 C 程 序 有 且 仅 有 一 个 main 函 数 main+ 若 干 子 函 数 ==>C 程 序 (2)C 从 语 法 上 无 函 数 与 过 程 之 分, 统 称 为 函 数 无 返 回 值 的 函 数 其 实 就 是 一 个 过 程,C 的 新 标 准 及 C++ 中 要 求 将 这 种 函 数 的 返 回 值 定 义 为 void 类 型 (3) 所 有 函 数 的 地 位 都 是 相 同 的, 不 允 许 嵌 套 定 义 (4) 注 解 : 增 加 易 读 性 (5) 自 由 书 写 格 式 : 一 语 句 可 分 几 行, 一 行 可 写 多 个 语 句 一 般 要 求 缩 排 3.2 C 语 言 语 法 描 述 最 常 用 的 语 法 规 则 描 述 工 具 是 Backus-Naur 范 式 (BNF) 和 语 法 图 两 种, 由 于 后 者 更 加 直 观, 本 课 采 用 语 法 图 描 述 圆 圈, 即 或 : 表 示 基 本 符 号 方 框, 即 : 引 用 另 一 个 语 法 图 箭 头, 即 : 语 法 的 合 法 走 向
3.3 字 符 和 词 法 单 位 一. 语 言 的 最 基 本 单 位 是 字 符 : 字 符 > 词 > 语 句 > 函 数 > 程 序 C 语 言 采 用 ASCII 字 符 集 二. 词 法 单 位 : (1) 标 识 符 : 在 高 级 语 言 中, 任 何 对 象 都 有 一 个 名 标 识 符 这 些 对 象 包 括 : 函 数 变 量 符 号 常 量 数 组 数 据 类 型 宏 等 标 识 符 其 实 就 是 字 母 打 头 的 字 母 数 字 序 列, 注 意 : (a) 长 度 : 早 期 的 C 编 译 程 序 只 认 前 8 个 字 符 VC 允 许 256 个 字 符 但 一 般 不 要 超 过 31 个 字 符 为 宜 (b) 约 定 : 变 量 名 函 数 名 和 数 据 类 型 名 等 用 小 字 母 ; 符 号 常 量 名 及 宏 用 大 写 字 母 ; 下 划 线 开 头 的 名 字 常 为 系 统 程 序 ( 库 函 数 用 ), 用 户 一 般 不 用 (c) 要 有 意 义 : 如 用 Sum 表 示 求 和 变 量, 不 要 用 aaa,a1, B12 之 类 名 字 参 见 p15~p16 (2) 关 键 字 : 也 称 保 留 字, 程 序 员 不 可 用 之 作 为 自 己 定 义 的 变 量 或 函 数 的 名 字 P12 表 2-1 (3) 界 限 符 : 运 算 符 分 隔 符 语 句 括 号 等 (4) 常 量 : 整 常 数 数 值 常 数 p17 字 符 常 数 字 符 串 常 数 符 号 常 数 实 常 数 (a) 字 符 常 量 : 字 符 转 义 字 符 每 个 字 符 常 数 占 一 个 字 节 每 个 字 符 常 数 有 一 个 编 码 数 字 值 ASCII 码 表 中 的 码 值 例 如 : A :65 B :66 a :97 b :98... 字 符 常 量 可 象 数 值 量 一 样 进 行 运 算 比 较 例 1:if(c>= A &&c<= Z ) c=c+ a - A ; 将 字 符 变 量 c 从 大 写 字 母 转 为 小 写 字 母 例 2: 0-0 =0 1-0 =1 2-0 =2 如 果 c 是 一 数 字 字 符, 则 c- 0 就 是 它 对 应 数 字 的 数 值 转 义 字 符 : 非 图 形 字 符 ( 如 回 车 制 表 符 等 ) 及 \ 等 字 符, 因 它 们 有 特 殊 作 用, 所 以 表 示 这 些 字 符 本 身 时, 应 :p18 位 模 式 : 用 来 表 示 无 法 用 其 它 方 法 表 示 的 字 符,\ddd: 一 至 三 位 8 进 制 数 例 如 : \001 表 示 码 值 为 (01) 8 的 ASCII 字 符 A 也 可 用 \101 表 示 \0 为 空 白 符, 即 NUL, 码 值 为 0, 在 C 语 言 中 是 字 符 串 的 结 束 标 志 ( 与 0 和 空 格 符 不 同 )
(b) 字 符 串 常 数 : 字 符 转 义 字 符 如 ABC \n GOOD BYE 等 注 意 P 与 P 不 同 前 者 为 字 符 串, 在 机 内 存 储 形 式 为 P \0, 而 P 就 是 一 常 数 P (c) 符 号 常 数 : 为 便 于 编 程, 为 某 个 常 数 所 起 的 符 号 名 例 如 :#define PI 3.1415926 参 见 p20 常 量 定 义,C++ 中 新 增 功 能, 同 PASCAL 中 的 常 量 3.4 基 本 的 输 入 和 输 出 处 理 3.4.1 I/O 流 控 制 这 是 C++ 中 新 加 的 非 常 简 单 易 用 的 输 入 输 出 方 式 1) 用 插 入 操 作 符 << 向 标 准 输 出 流 cout 输 出 p22 2) 用 抽 取 操 作 符 >> 从 标 准 输 入 流 cin 中 输 入 p22 3) 使 用 控 制 符 有 时 缺 省 输 出 格 式 不 能 满 足 要 求, 这 时 可 以 用 控 制 符 控 制 输 出 的 格 式 p23 表 2-4 例 ch2_1.cpp 3.4.2 传 统 的 C 语 言 标 准 输 入 / 输 出 函 数 C 语 言 没 有 专 门 的 I/O 命 令, 利 用 库 函 数 实 现 数 据 的 输 入 输 出 1) 用 printf 函 数 进 行 数 据 的 输 出 形 式 :printf( 格 式 控 制 串, 参 数 1, 参 数 2, ) 按 格 式 控 制 串 指 定 的 格 式 在 标 准 输 出 设 备 上 输 出 各 参 数 所 指 定 的 内 容 p28 例 及 格 式 符 介 绍 2) 用 scanf 进 行 变 量 数 据 的 输 入 格 式 :scanf( 格 式 控 制 串, 参 数 1, 参 数 2, ) 格 式 串 的 意 义 与 printf 中 一 样, 但 其 转 换 方 向 是 输 入 到 变 量 要 特 别 注 意 参 数 中 的 取 地 址 操 作 & 是 必 不 可 少 的 p31 例 3) 用 getchar 和 putchar 进 行 单 个 字 符 的 输 入 和 输 出 形 式 :getchar( ) 从 终 端 输 入 字 符 流 中 取 下 一 字 符, 并 返 回 其 代 码 值, 用 法 : char c; c=getchar(); 形 式 :putchar(c ) 在 终 端 上 输 出 字 符 型 变 量 c 所 代 表 的 字 符 相 当 于 printf( %c,c); 例 :#include<stdio.h> main() {char c1,c2,c3; c1=getchar(); c2=getchar(); c3=getchar(); putchar(c1); putchar(c2); putchar(c3); putchar( \n );
3.5 函 数 的 初 步 介 绍 函 数 是 C 程 序 的 基 本 组 成 单 位, 有 两 种 函 数 : (1) 系 统 定 义 的 库 函 数 ( 如 printf scanf 等 ) (2) 用 户 在 程 序 中 定 义 的 函 数 类 型 函 数 名 ( ) 参 数 表 参 数 说 明 函 数 体 p9 例 ch1_3.cpp 函 数 体 : { 内 部 数 据 说 明 语 句 调 用 函 数 : 被 调 函 数 名 ( ) 实 参 表 调 用 与 返 回 : 从 main 函 数 的 第 一 句 开 始 执 行, 遇 return 语 句 返 回. 3.6 运 行 C 语 言 程 序 的 全 过 程 p6 图 1-1 编 辑 编 译 调 试 运 行 第 4 章 基 本 数 据 类 型 和 运 算 表 达 式 整 型 : 短 整 长 整 无 符 号 标 准 数 据 类 型 实 型 : 单 精 度 双 精 度 字 符 (char) 逻 辑 型 (bool)(c++) 枚 举 型 数 据 类 型 数 组 (p14 表 2-2) 组 合 数 据 类 型 结 构 (struct) 联 合 (union) 类 (class)(c++) 指 针 类 型 空 类 型 (void) 用 户 定 义 数 据 类 型 4.1 变 量 和 类 型 说 明 常 量 : 固 定 不 变 的 值,C 中 用 符 号 常 数 来 表 示, 无 须 定 义 类 型 ; C++ 中 可 以 定 义 常 量 (const) 变 量 : 需 要 定 义, 说 明 其 存 储 属 性 和 数 据 类 型 存 储 属 性 static extern register auto 类 型 区 分 符 int char float double 变 量 名, 赋 定 初 值 ; 例 :static int nward=0, nkayword; 4.2 标 准 数 据 类 型 p14 表 2-2 注 意 整 型 和 实 型 的 几 种 不 同 方 式 注 意 各 种 数 据 类 型 的 取 值 范 围
注 意 C 无 布 尔 类 型 C 语 言 在 表 达 逻 辑 运 算 的 结 果 时, 用 整 数 0 代 表 逻 辑 假, 用 非 0 的 整 数 值 ( 如 1) 表 示 逻 辑 真 C++ 中 增 添 了 布 尔 类 型 bool, 但 并 非 每 个 C++ 编 译 器 都 支 持 4.3 枚 举 类 型 实 际 上 是 一 种 用 户 定 义 的 数 据 类 型, 是 C 语 言 新 版 本 中 新 增 的 enum 枚 举 类 型 名 { 枚 举 值 标 识 符 p20, ; 4.4 数 据 类 型 转 换 C 语 言 中, 当 表 达 式 中 对 象 类 型 不 一 致 时, 要 进 行 转 换, 规 则 : (1)char, short int ; float double ( 必 定 的 转 换 ) (2) 级 别 由 低 高, 表 达 式 最 后 值 是 级 别 高 的 那 个 类 型 p38 (3) 赋 值 表 达 式 E1=E2, 将 E2 结 果 值 转 换 成 E1 类 型 后 进 行 赋 值 (4) 强 制 类 型 转 换 :( 类 型 名 ) 表 达 式 虽 然 C 在 对 不 同 类 型 对 象 混 合 运 算 时, 能 自 动 进 行 类 型 转 换, 但 编 程 时 仍 应 尽 量 避 免 4.5 运 算 符 及 运 算 表 达 式 * 表 达 式 就 是 由 操 作 数 运 算 符 构 成 的 一 个 操 作 序 列,P35 表 3-1 列 出 了 C++ 的 全 部 运 算 符 的 功 能 优 先 级 和 结 合 性 规 则 (1) 算 术 运 算 符 : + - * / %( 取 模 ) 在 C 中, 若 / 的 两 操 作 数 都 为 整 数, 则 为 整 除 : 例 : int i = 15; float f ; f = i/10; printf ( f=%f\n, f); 则 结 果 为 :f=1.000000 如 果 将 第 三 条 语 句 改 为 : f = (float)i/10; 或 f = i/10.0; 则 结 果 为 :f=1.500000 (2) 关 系 运 算 符 > >= < <= = =!= 注 意 = = 在 程 序 中 不 要 误 用 为 = (3) 逻 辑 运 算 符 : &&! 真 值 表 如 下 (T 表 示 真,F 表 示 假 ): a b!a!b a&&b a b T T F F T T T F F T F T F T T F F T F F T T F F 注 意 : 对 mini <= value <= max C 编 译 不 会 报 错, 但 结 果 不 对, 所 以 编 程 时 要 注 意, 不 要 以 为 C 可 以 这 样 用 应 该 用 mini<= value && value <= max 进 行 判 断
(4) 增 1 和 减 1 运 算 即 ++ 和 -- 运 算 C 特 色, 对 于 构 造 简 单 灵 活 的 表 达 式 很 有 用 两 种 用 法 前 缀 用 法 ++i,--i 先 加 1, 再 引 用 i 的 值 后 缀 用 法 i++,i-- 先 引 用 i 的 值, 再 加 1 都 是 将 变 量 i 的 值 加 1( 减 1) 例 :i=10; a=i++; 则 a 的 值 为 10,i 的 值 为 11 而 a= --i; 则 a 的 值 为 9,i 的 值 也 为 9 同 样 :s[i++]=c; 等 价 于 s[i]=c; i=i+1; s[++i]=c; 等 价 于 i=i+1; s[i]=c; 注 意 :(1)++ -- 只 适 用 于 整 型 变 量 (2) 不 引 用 表 达 式 值, 只 需 对 变 量 加 1( 减 1) 时, 两 法 相 同 (3) 注 意 副 作 用 p40~41,p49 (5) 字 位 逻 辑 运 算 符 & 按 位 与, 两 操 作 数 按 位 求 与 按 位 或, 两 操 作 数 按 位 求 或 ^ 按 位 加, 两 操 作 数 按 位 求 异 或 << 将 左 操 作 数 左 移 右 操 作 数 给 出 的 位 数 >> 将 左 操 作 数 右 移 右 操 作 数 给 出 的 位 数 ~ 按 位 求 反 例 :int i=4, j=6; i 的 内 码 00000000 00000100 j 的 内 码 00000000 00000110 则 k=i&j 的 结 果 为 4 k=i j 的 结 果 为 6 k=i^j 的 结 果 为 2 & 常 用 来 屏 蔽 某 些 字 位, 如 x=x & ~077 置 x 的 后 6 为 0 常 用 于 将 某 些 位 置 为 1, 如 x=x 02 将 x 的 第 2 位 置 为 1 << 和 >> 要 求 右 数 为 正 整 数 且 小 于 左 数 的 字 位 长 度 例 如 i<<3 相 当 于 i = i*8(2 3 ) 所 以, 字 位 逻 辑 运 算 使 C 语 言 能 象 汇 编 语 言 那 样 灵 活 地 处 理 硬 件 机 器 字 (6) 赋 值 运 算 和 自 反 赋 值 运 算 (a)c 语 言 中 = 是 运 算 符 p34 (b)c 允 许 多 重 赋 值 :x=y= i*j; (c) 自 反 赋 值,C 独 有 的 一 套 运 算 符 多 数 二 目 运 算 符 (op) 都 有 其 对 应 的 自 反 运 算 符 op=, 规 则 :p37 E1 op= E2 等 价 于 E1 = (E1) op (E2) 例 如 :i *= i*p+q 等 价 于 i = i*(i*p+q) a+=a-=a*a 等 价 于 a=a-a*a; a=a+a; (7) 逗 号 运 算 符 用 于 将 两 个 表 达 式 组 合 成 一 个 表 达 式 :E1,E2 从 左 向 右 计 算, 结 果 的 类 型 和 值 为 E2 的 类 型 和 值 例 如 :t=2,t+3 则 最 后 表 达 式 的 值 为 5,t 的 值 为 2 在 逗 号 有 特 殊 意 义 的 上 下 文 中, 逗 号 表 达 式 必 须 加 括 号 :
例 如 :f1(a,(t=2,t+3),c) 常 用 于 for 语 句 中, 可 控 制 多 个 初 值 或 循 环 控 制 变 量 (8) 条 件 运 算 符 E1?E2:E3 先 计 算 E1 的 值 如 为 真, 计 算 E2, 且 此 值 是 该 表 达 式 的 值 如 为 假, 计 算 E3, 且 此 值 是 该 表 达 式 的 值 例 :z = (a>b)? a : b 就 是 求 a 和 b 的 最 大 值, 将 其 赋 值 给 变 量 z 4.6 计 算 顺 序 和 优 先 级 按 照 p35 表 3-1 运 算 符 的 优 先 级 和 结 合 性 : 先 高 优 先 级, 后 低 优 先 级 同 优 先 级, 按 结 合 性 从 左 到 右 或 从 右 到 左 进 行 计 算 C 运 算 符 及 优 先 级 别 较 多, 必 要 时 可 加 上 括 号 以 增 强 可 读 性 和 安 全 性 第 5 章 语 句 和 流 程 控 制 在 程 序 设 计 语 言 中, 每 条 语 句 都 是 一 条 命 令, 要 求 计 算 机 完 成 完 成 一 定 的 功 能 若 干 条 语 句 的 合 理 组 合, 就 描 述 了 我 们 解 决 某 种 问 题 的 算 法, 构 成 程 序 5.1 表 达 式 语 句 语 法 : 表 达 式 ; 注 意 :(1) 关 于 ; 号, 在 C 中 它 是 语 句 的 一 部 分, 是 语 句 的 终 止 符, 而 不 象 PASCAL 等 语 言 那 样 是 语 句 间 的 分 隔 符 (2) 要 有 实 际 意 义, 即 通 过 语 句 的 执 行 使 程 序 的 状 态 发 生 一 定 的 变 化 如 i++; a=getchar(); 而 a+b; 则 没 有 任 何 意 义 5.2 复 合 语 句 和 分 程 序 语 法 :{----; ----; ----; 结 束 复 合 语 句 的 之 后 不 需 再 加 ; 号 分 程 序 : 结 构 化 程 序 设 计 的 基 本 设 施, 变 量 作 用 域 仅 在 { 内 部 语 法 : { 变 量 类 型 说 明 ------; ------; 例 如 :{int c; c=getchar(); putchar(c); 5.3 空 语 句 语 法 : 仅 有 一 个 ; 号 为 goto 语 句 提 供 标 号 或 辅 助 其 它 语 句 的 书 写 5.4 if 语 句 语 法 :if( 表 达 式 ) 语 句 1 [else 语 句 2] 例 :if(a>b) z=a; 分 号 不 能 少 else z=b; if(a>b) {z=a; a++; else z=b; 分 号 不 能 加
p45 例 注 意 :(1) 因 为 ( ) 中 是 表 达 式, 所 以 允 许 出 现 = 号, 因 此 要 特 别 当 心 不 要 将 = = 误 写 为 = (2) 注 意 分 号 的 问 题,C 语 言 中 分 号 是 语 句 的 一 部 分 (3)p46 解 决 二 义 性 5.5 循 环 语 句 循 环 语 句 用 于 控 制 其 它 语 句, 使 之 重 复 执 行 若 干 次, 称 为 循 环 按 照 控 制 方 式 的 不 同,C 语 言 中 提 供 了 三 种 不 同 的 循 环 语 句 5.5.1 while 语 句 语 法 :while ( 表 达 式 ) 语 句 S p54 图 4-1 例 ch4_1.cpp 5.5.2 do while 语 句 语 法 :do 语 句 S while( 表 达 式 ); p56 图 4-2 例 ch2_2.cpp 5.5.3 for 语 句 语 法 :for([ 表 达 式 1];[ 表 达 式 2];[ 表 达 式 3]) 语 句 S p58 图 4-3,for 的 执 行 流 程 注 意 :C 的 for 语 句 与 其 它 高 级 语 言 中 的 for 语 句 大 不 相 同 其 它 语 言 中,while 语 句 的 循 环 次 数 在 运 行 过 程 中 根 据 情 况 而 定, 而 for 语 句 则 执 行 事 先 给 定 次 数 的 循 环 如 : FOR i=1 TO 10 DO 但 在 C 中,for 语 句 同 时 具 有 while 的 功 能, 可 以 用 while 描 述 for 的 功 能 : 表 达 式 1; while( 表 达 式 2) { 语 句 S 表 达 式 3; 总 结 :C 中 for 的 执 行 机 理 与 while 是 一 样 的, 但 它 比 while 更 灵 活, 它 不 仅 可 以 用 于 循 环 次 数 已 经 确 定 的 情 况, 而 且 可 用 于 循 环 次 数 不 定 的 情 况 p58 灵 活 性 例 :for(i=0;(s[i]=getchar())!=eof;i++); i=0; s[i]=getchar(); while(s[i]!=eof) s[++i]=getchar(); 等 价 于 相 关 语 句 : (1) return 语 句 :return( 表 达 式 ) 或 return (2) break 语 句 : 退 出 循 环 体 或 switch 语 句 p64 例 :while(1) { ------; ------; if(---) break; (3)continue 语 句 : 跳 过 剩 余 循 环 体, 进 入 下 一 次 循 环 p64,65 5.6 开 关 语 句
语 法 :switch( 表 达 式 ) { case 常 量 1: 成 分 子 语 句 1;break; case 常 量 2: 成 分 子 语 句 2;break; case 常 量 n: 成 分 子 语 句 n;break; [default: 成 分 子 语 句 n+1] 注 意 : 在 case 子 句 中 要 正 确 运 用 break 语 句 p61 例 :switch(i) { case 1: case 2: case 3: case 4: a=a+b*10; break; case 5: a=a*c; case 6: a++; 5.7 goto 语 句 语 法 :goto 语 句 标 号 ( 标 识 符 ) p65 例 注 意 : 标 号 的 作 用 域 : 当 前 函 数 5.8 语 句 使 用 实 例 p66~p73 编 程 关 键 : (1) 确 定 求 解 问 题 的 算 法 (2) 熟 悉 各 种 语 句 的 功 能 和 特 性 (3) 以 合 理 的 程 序 结 构 ( 如 ch4_9.cpp) 利 用 相 关 语 句 将 算 法 描 述 出 来 p73 小 结 第 6 章 数 组 数 组 是 由 相 同 类 型 的 成 分 分 量 组 成 的 有 序 数 据 集 合 当 需 要 使 用 大 量 集 中 在 一 起 的 数 据 来 工 作 时, 就 可 以 使 用 数 组 来 满 足 这 一 要 求 6.1 数 组 定 义 和 数 组 元 素, 存 储 属 性 类 型 数 组 名 [ 整 常 表 达 式 ] 初 值 例 :int ndigit[10]; static char s[leng], ds[3][3]; int array[]={1,2,3,4,5; p120 图 7-1 例 数 组 元 素 引 用 : 数 组 是 由 连 续 的 存 储 单 元 组 成, 起 始 地 址 为 数 组 的 第 一 个 元 素, 每 个 元 素 都 有 一 个 下 标, 它 是 该 元 素 距 离 第 一 个 元 素 的 偏 移 量 数 组 中 特 定 的 元 素 通 过 下 标 访 问 (p120 图 7-1): ; 数 组 名 [ 整 型 表 达 式 ]
注 意 :(1) C 语 言 中, 数 组 下 标 是 从 0 开 始 的, 一 个 长 度 为 n 数 组, 其 n 个 元 素 的 下 标 分 别 为 0~(n-1) ndigit[0], ndigit[1],, ndigit[9] ss[0][0], ss[0][1], ss[0][2],, ss[2][2] p123 Fibonacci 例 (2) 当 说 明 中 表 达 式 为 空, 只 有 [ ] 时, 数 组 长 度 由 以 下 因 素 决 定 : a. 如 同 时 给 出 初 值, 则 由 初 值 个 数 决 定 b. 已 在 其 它 场 合 说 明 了 它 的 长 度 ( 如 形 参 外 部 数 组 等 ) 6.2 字 符 数 组 这 是 C 语 言 中 最 常 用 的 数 组, 由 于 C 语 言 中 没 有 专 门 的 字 符 串 类 型, 对 字 符 串 的 处 理 是 通 过 字 符 数 组 进 行 的 C 语 言 约 定 每 个 字 符 串 以 \0 作 为 结 束 标 志 如 :char line[100]; 可 用 来 存 放 最 长 为 99 个 字 符 的 串 line a d o g \0, 012345, 99 例 :p123 ch7-1.cpp 注 意 : (1) 不 能 用 scanf 输 入 一 个 带 空 格 的 串 (cin>>str 也 一 样 ) 如 :char str[13]; scanf( %s,str); 如 果 输 入 How are you? 则 str 的 内 容 为 : Ho w\0 (2) 可 以 用 C 的 库 函 数 gets(str) 或 C++ 的 cin.getline(str, 80) 输 入 带 空 格 的 串 p124 例 7_1.cpp (3)scanf 中 的 输 入 项 是 数 组 名, 不 要 再 加 &: scanf( %s,str); (4) 字 符 串 处 理 函 数 puts( 字 符 串 ) gets( 字 符 数 组 ) strcat( 字 符 数 组 1, 字 符 数 组 2) strcpy( 字 符 数 组 1, 字 符 串 2) strcmp( 字 符 串 1, 字 符 串 2) strlen( 字 符 串 ) strlwr( 字 符 串 ) strupr( 字 符 串 ) 6.3 多 维 数 组 当 组 成 一 个 数 组 的 每 个 元 素 也 是 数 组 时, 便 为 多 维 数 组 #define I 3 #define J 5 int tab[i][j]; 则 tab 是 一 个 有 I*J 个 元 素 的 数 组, 共 有 I 行 J 列 存 放 时 是 按 行 存 放 的 参 见 p130 图 7_4 可 以 将 多 维 数 组 看 成 是 元 素 为 数 组 的 一 维 数 组 6.4 数 组 的 初 值 初 值 : = 字 符 串 { 初 值 符 表
初 值 符 表 : 常 数 表 达 式 初 值 符 表, { 初 值 符 表 例 :char string[]= INTRODUCTION ; char string[]={ INTRODUCTION ; char string[]={ I, N, T, R,, N, \0 ; int x[2][2]={{1,2,3,{4,5,6; 或 {1,2,3,4,5,6; C 限 制 :(1) 静 态 数 组 (2) 外 部 数 组 才 能 赋 初 值 但 C++ 中 自 动 数 组 也 行 p125 例 ch7-2.cpp 7.1 函 数 的 基 本 结 构 第 7 章 函 数 和 程 序 结 构 static 函 数 类 型 头 参 数 说 明 函 数 体 函 数 类 型 头 : 简 单 类 型 类 型 区 分 符 * 函 数 名 ( 参 数 ), p78, 几 种 不 同 类 型 的 函 数 调 用 函 数 : 被 调 函 数 名 ( ) 实 参 表 按 语 法 图,C 语 言 中 不 允 许 在 一 个 函 数 内 定 义 另 一 个 函 数 函 数 之 间 的 通 信 : (1) 通 过 实 参 形 参 (2) 通 过 返 回 值 (3) 通 过 全 程 外 部 变 量 7.2 函 数 的 参 数 为 使 函 数 具 备 更 大 的 灵 活 性, 对 不 同 变 量 进 行 相 同 功 能 的 处 理 (1) 参 数 说 明 : 类 型 区 分 符 参 数 名 ; register, 与 变 量 定 义 很 类 似, 但 存 储 属 性 不 能 是 static 或 extern (2) 形 参 的 生 存 期 : 同 所 在 函 数 的 生 存 期 (3) 参 数 的 值 传 送 性 质 : 实 参 形 参 之 间 共 有 传 值 传 地 址 两 种 传 递 方 式,C 语 言 中 只 支 持 传 值
由 于 是 传 值, 所 以 在 函 数 中 对 形 参 的 改 变 不 影 响 对 应 的 实 参 当 形 参 为 数 组 时, 对 应 的 实 参 应 为 数 组 名 此 时 仍 然 是 传 值, 只 不 过 该 值 恰 好 是 数 组 的 首 地 址, 因 为 在 C 中, 数 组 名 就 代 表 该 数 组 的 首 地 址, 可 以 将 其 当 常 量 来 用 指 针 参 数 的 处 理 : 还 是 传 值, 此 值 是 该 指 针 所 代 表 的 地 址 值 所 以 要 切 记,C 语 言 中 形 实 参 之 间 只 有 一 种 传 递 方 式, 即 传 值 (4) 注 意 参 数 的 求 值 顺 序 (5) 某 些 C 编 译 器 允 许 实 参 和 形 参 的 个 数 可 以 不 同, 当 实 参 个 数 少 时, 多 出 的 形 参 取 出 的 是 无 意 义 的 数 据 ; 当 实 参 个 数 多 时, 多 给 的 实 参 没 有 用 (6)p84~85 函 数 调 用 机 制, 注 意 其 中 形 实 参 间 的 值 传 送 方 式 7.3 函 数 类 型 即 函 数 返 回 值 的 类 型 调 用 函 数 前 必 须 对 其 说 明,int 型 可 缺 省 7.4 变 量 存 储 属 性 * (1)C 源 文 件 的 组 成 及 编 译 运 行 环 境 (i) 源 文 件 的 组 成 : 一 个 C 程 序 由 若 干 函 数 外 部 数 据 定 义 预 处 理 部 分 组 成, 它 们 可 以 存 放 在 一 个 源 文 件 中, 也 可 以 分 散 存 放 在 多 个 源 文 件 中 : s.c #define... 外 部 定 义 main( ) {...... f1( ) {...... f2( ) {...... 方 式 1 s1.c #define... 外 部 定 义 main( ) {...... s2.c f1( ) {...... f2( ) {...... 方 式 2 分 成 多 个 源 文 件 的 好 处 : 便 于 多 人 合 作 ( 大 工 程 ) 便 于 调 试 ( 分 步 编 译 ) (ii)c 编 译 a. 直 接 编 译 :cc -o exec s1.c s2.c< 回 车 > b. 分 步 编 译 : 先 生 成 浮 动 安 装 码, 再 连 接 生 成 目 标 程 序 : cc -c s1.c< 回 车 > 将 生 成 s1.o(.obj) cc -c s2.c< 回 车 > 将 生 成 s2.o(.obj) cc -o exec s1.o s2.o< 回 车 > 采 用 分 步 编 译 时, 如 果 对 f2() 中 做 了 修 改, 只 需 重 新 编 译 s2.c, 再 与 s1.o 连 接 即 可 (2) 变 量 的 存 储 属 性 即 变 量 的 生 存 期 及 作 用 域 :auto, static, extern, register 7.5 自 动 变 量 即 某 函 数 中 的 局 部 变 量 其 生 存 期 同 所 在 函 数 ; 作 用 域 在 所 在 函 数 之 内 它 是 在 函 数 被 调 用 时 在 栈 中 临 时 分 配 空 间 的 p81 及 p85 图 8-5, 注 意 其 中 的 局 部 变 量 a, b, n, x 等 在 栈 中 的 空 间 分 配
7.6 外 部 变 量 外 部 变 量 是 在 任 何 函 数 外 部 定 义 的 变 量, 可 被 多 个 函 数 共 用 外 部 变 量 在 程 序 运 行 期 间 永 远 存 在, 它 是 在 编 译 时 静 态 分 配 的 空 间 如 p81 程 序 段 中 的 n 可 以 通 过 外 部 变 量 在 函 数 间 隐 式 传 递 数 据 如 果 一 个 全 程 外 部 变 量 与 一 个 函 数 ( 或 分 程 序 ) 中 的 自 动 变 量 同 名, 在 C 语 言 中 是 允 许 的, 但 它 们 各 自 的 生 存 期 和 作 用 域 是 不 同 的 p110~111 7.7 作 用 域 规 则 自 动 变 量 所 在 函 数 外 部 变 量 源 文 件 说 明 它 的 地 方 直 到 该 文 件 的 结 束 注 意 : (1) 下 述 情 况 下 必 须 使 用 extern 说 明 :p101 上 的 n a. 定 义 外 部 变 量 的 程 序 和 使 用 该 变 量 的 程 序 不 在 同 一 源 文 件 b. 外 部 变 量 在 定 义 之 前 就 要 被 某 一 函 数 使 用 (2) 在 组 成 一 个 C 程 序 的 所 有 源 文 件 中, 对 一 个 外 部 变 量 有 且 只 能 有 一 个 定 义, 其 余 的 为 extern 说 明 ( 变 量 初 值 数 组 长 度 等 在 变 量 定 义 时 指 明 ) s.c int i; char s[100]; float f=1.5; main( ) {...... f1( ) {...... f2( ) {...... 方 式 1 s1.c s2.c int i; char s[100]; float f=1.5; main( ) {...... extern int i; extern char s[]; extern f; f1( ) {...... f2( ) {...... 注 意 变 量 的 定 义 和 变 量 的 说 明 不 同 : 定 义 : 要 在 编 译 时 或 在 栈 中 分 配 空 间 说 明 : 引 用 其 它 源 文 件 或 本 文 件 后 面 定 义 的 变 量, 不 分 配 存 储 空 间, 只 是 说 明 该 变 量 是 有 定 义 的 方 式 2 7.8 静 态 变 量 静 态 变 量 (static) 分 为 两 种 情 况 : (1) 静 态 自 动 变 量 : 延 长 其 生 存 期 至 整 个 程 序 执 行 结 束 ( 下 次 再 进 入 该 函 数 时 值 还 在 ) (2) 静 态 外 部 变 量 : 缩 小 其 作 用 域 至 所 在 的 源 文 件 ( 多 人 合 作 时 避 免 冲 突, 增 加 安 全 性 ) p102~104 静 态 函 数 : 函 数 在 缺 省 情 况 下 都 是 全 程 外 部 的, 而 静 态 函 数 类 似 于 静 态 外 部 变 量, 是 将 函 数 的 作 用 域 缩 小 到 其 所 在 的 源 文 件 p104 7.9 寄 存 器 变 量 指 定 硬 件 寄 存 器 作 为 变 量 的 存 储 位 置 register int i; i++; 快! 对 频 繁 使 用 的 整 型 字 符 型 变 量 可 用 register 注 意 : (1)register 只 适 用 于 auto 和 形 参
(2) 为 整 型 时,int 可 省 (3) 与 机 器 硬 件 有 关, 不 能 保 证 该 变 量 一 定 存 放 到 寄 存 器 中 (4) 不 能 进 行 取 地 址 操 作 (&), 不 能 存 放 组 合 型 变 量 例 :auto_static() { int auto_var=0; static int static_var=0; printf( auto=%d, static=%d\n, auto_var, static_var); ++auto_var; ++static_var; main() { int i; for(i=0;i<4;i++) auto_static(); 7.10 函 数 的 递 归 调 用 函 数 可 以 直 接 或 间 接 调 用 自 身, 称 为 递 归 调 用 并 不 是 每 种 程 序 设 计 语 言 都 支 持 函 数 的 递 归 调 用, 但 PASCAL C 都 支 持 例 如 计 算 阶 乘 n!, 因 为 n! = n*(n-1)!, 所 以 可 以 用 递 归 函 数 实 现 对 阶 乘 的 计 算 p87,88 例 注 意 :(1)p88 其 中 最 重 要 的 是 之 前 设 定 递 归 结 束 条 件 (2) 递 归 调 用 不 是 必 须 的, 很 多 情 况 下 可 化 为 非 递 归 p89 (3) 递 归 调 用 可 以 简 化 程 序 的 设 计, 使 之 易 读, 但 执 行 效 率 并 不 高 7.11 内 联 函 数 C++ 新 增 主 要 目 的 是 提 高 程 序 的 运 行 效 率, 作 用 类 似 于 原 C 中 的 宏 p90 定 义 方 法 : 在 一 般 的 函 数 定 义 前 加 inline 关 键 字 p91 注 意 :(1) 必 须 在 第 一 次 被 调 用 前 即 声 明 为 inline p91 (2) 内 联 函 数 中 不 使 用 复 杂 的 流 程 控 制 语 句, 如 for, switch 等, 如 果 有, 将 被 视 为 普 通 函 数 处 理 (3) 注 意 它 与 #define 所 定 义 的 宏 的 异 同 p92 7.12 重 载 函 数 C++ 新 增 目 的 是 增 加 函 数 的 灵 活 性, 使 程 序 更 易 读 易 书 写 p93 求 绝 对 值 例 当 两 个 函 数 的 参 数 个 数 参 数 类 型 或 返 回 值 类 型 不 同, 但 函 数 名 相 同 时, 称 之 为 函 数 重 载 注 意 :(1) 重 载 函 数 的 匹 配 p94 (2) 重 载 函 数 如 果 仅 仅 是 返 回 值 类 型 不 同 是 不 够 的 p94 (3) 不 能 用 typedef 定 义 的 类 型 名 来 区 分 重 载 函 数 中 参 数 的 类 型 (4) 应 该 让 重 载 函 数 对 不 同 的 参 数 完 成 相 同 的 功 能 7.13 参 数 的 默 认 值 当 函 数 调 用 时, 如 果 实 参 缺 省, 对 应 的 形 参 就 设 为 事 先 确 定 的 默 认 值, 便 于 编 程 p95 注 意 :(1) 参 数 的 默 认 值 在 函 数 声 明 中 提 供, 当 只 有 定 义 时, 才 可 出 现 在 函 数 定 义 中
(2) 默 认 参 数 的 顺 序 规 定 : 应 从 右 至 左 逐 渐 定 义, 调 用 函 数 时 只 能 从 左 向 右 匹 配 参 数 p96 (3) 注 意 重 载 函 数 用 默 认 参 数 时 可 能 产 生 的 二 义 性 p96 (4) 默 认 值 可 以 是 一 个 全 局 变 量 全 局 常 量 甚 至 是 一 个 函 数, 但 不 能 是 局 部 变 量 第 8 章 指 针 8.1 指 针 的 概 念 (1) 定 义 : 一 个 指 针 其 实 就 是 一 个 地 址, 相 当 于 日 常 生 活 中 的 路 标 或 指 路 牌, 能 够 提 供 对 变 量 空 间 的 间 接 访 问 一 个 指 针 变 量 中 存 放 的 就 是 另 一 个 数 据 对 象 的 内 存 地 址 例 :int *pi; 定 义 了 一 个 指 向 整 型 量 的 指 针 关 于 取 地 址 运 算 符 &: & 变 量 名 作 用 : 取 变 量 名 所 指 变 量 的 地 址 例 :int i, *pi; pi = &i; 则 将 pi 指 向 变 量 i: 0x2FFF 300 0x2FFF pi i 指 针 变 量 定 义 : 类 型 区 分 符 * 说 明 符 ; 说 明 符 : 标 识 符, int *pi; * 说 明 符 说 明 符 ( ) 说 明 符 [ 表 达 式 ] ( 说 明 符 ) int **i; int *f(); int *a[]; int (*f)(); 指 针 定 义 例 子 : int *pi; 指 向 整 型 量 的 指 针 ( 类 似 的 :char *pc; ) int *f(); 函 数 f 的 返 回 值 是 一 个 指 向 整 型 量 的 指 针 int (*pfi)(); pfi 是 指 向 函 数 的 指 针, 该 函 数 的 返 回 值 为 int int *api[4]; api 是 长 度 为 4 的 指 针 数 组, 其 每 个 元 素 是 一 个 指 向 整 型 量 的 指 针 int (*pai)[3]; pai 是 一 个 指 向 长 度 为 3 的 整 型 数 组 的 指 针 int *(*pfpi)(); pfpi 是 一 个 指 向 函 数 的 指 针, 该 函 数 的 返 回 值 为 指 向 整 型 量 的 指 针 int (*(*fap)[])(); fap 是 一 个 指 向 数 组 的 指 针, 该 数 组 是 一 个 指 针 数 组, 其 每 个 元 素 是 指 向 返 回 值 为 int 的 函 数 的 指 针 注 意 : 要 从 内 层 逐 层 向 外 读 (2) 指 针 的 使 用 定 义 了 一 个 指 向 特 定 类 型 的 指 针 后, 可 以 :
a. 赋 值 : 否 则 无 意 义 int i, *pi; pi = &i; b. 引 用 :*pi 取 pi 所 指 变 量 的 内 容 所 以 :i=0; 等 价 于 *pi=0; i++; 等 价 于 (*pi)++; 括 号 不 能 少, 因 为 : *pi++; 等 价 于 *pi; pi=pi+1; c. 复 写 :int x, *px, *py; px = &x; py = px; 使 指 向 相 同 注 意 :(1) 指 针 变 量 可 以 用 auto, register, static 和 extern 说 明 (2) 复 写 时 (px=py), 两 指 针 类 型 要 一 致 (3) 指 针 必 须 有 指 向 int *p; *p=2; 是 错 误 的 (4) 静 态 / 外 部 / 指 向 基 本 类 型 的 auto 指 针 可 以 赋 初 值 int k[5], i; int *ptr1 = &k[1], *ptr2 = &i; 8.2 指 针 与 函 数 C 的 函 数 参 数 是 传 值 的, 直 接 传 值 无 法 将 函 数 对 形 参 的 修 改 带 出, 但 实 际 应 用 中 常 有 这 种 需 要,C 语 言 中 可 以 利 用 指 针 实 现 以 交 换 两 个 变 量 值 的 过 程 为 例 : swap1(int i, int j) {int temp; temp = i; i = j; j = temp; main() {int a=15, b=20; swap1(a,b); swap1 main temp b a 但 该 程 序 无 法 实 现 通 过 调 用 函 数 swap1 交 换 main 中 a 和 b 的 值 的 目 的, 因 为 : j i 20 15 20 15 i,j 交 换 a,b 不 受 影 响 用 指 针 改 写 上 述 程 序 : swap2(int *pi, int *pj) {int temp; temp = *pi; *pi = *pj; *pj = temp; swap2 main() {int a=15, b=20; swap2(&a, &b); main temp 2002 b 2000 a 2002 2000 20 15 但 该 程 序 可 以 实 现 通 过 调 用 函 数 swap2 交 换 main 中 a 和 b 的 值 的 目 的, 因 为 : 所 以, 虽 然 C 本 质 上 是 传 值 的, 但 通 过 指 针, 令 形 实 参 均 为 指 针, 便 可 使 形 实 参 指 向 同 一 对 象, 从 而 实 现 在 函 数 中 改 变 实 参 所 指 变 量 的 值 与 PASCAL 中 的 传 地 址 方 式 功 能 相 当, 但 需 要 用 户 自 己 负 责 地 址 传 递 这 也 是 为 什 么 scanf 参 数 前 要 加 & pj pi pi, pj 未 动 a,b 交 换
8.3 指 针 和 数 组 C 语 言 中 指 针 和 数 组 是 密 不 可 分 的, 且 同 样 的 问 题 用 指 针 处 理 速 度 更 快 对 数 组 元 素 的 存 取 可 以 通 过 下 标 来 确 定 元 素, 也 可 以 通 过 指 针 运 算 来 确 定 元 素 从 某 种 意 义 上 说, 指 针 就 是 数 组, 数 组 就 是 指 针 例 :int array[8], *parray; parray = array; 或 parray = &array[0]; 则 可 形 成 下 图 所 示 状 态 : array[0] [1] [2] [3] [4] [5] [6] array[7] parray 则 :*parray 等 价 于 array[0] 等 价 于 *array 等 价 于 parray[0] *(parray+i) 等 价 于 array[i] 等 价 于 *(array+i) 等 价 于 parray[i] parray+i 等 价 于 &array[i] 等 价 于 &parray[i] 数 组 名 与 指 向 该 数 组 首 址 的 指 针 的 区 别 在 于 : 数 组 名 不 是 变 量, 不 能 array++, 但 parray++ 可 以 函 数 参 数 中 的 数 组 名 p162 当 实 参 是 数 组 名 时, 对 应 的 形 参 有 两 种 定 义 方 法, 以 字 符 数 组 为 例 : main( ) {char name[10];...... slength(name);...... slength(s1) char s1[]; {...... 或 slength(s1) char *s1; {...... 形 参 的 两 种 定 义 方 法 作 用 完 全 相 同, 因 为 在 C 中 数 组 名 就 代 表 数 组 的 首 地 址 : name p162 图 8-7 s1 结 论 :C 语 言 中, 指 针 和 数 组 是 密 不 可 分 的,C 语 言 数 组 实 际 上 就 是 指 针,C 用 指 针 + 运 算 符 [] 模 拟 了 数 组 的 概 念, C 编 译 器 只 实 现 了 指 针, 并 未 实 现 数 组, 所 以 在 C 中 根 本 不 会 检 查 数 组 下 标 是 否 出 界 注 意 : 如 果 需 要 对 连 续 的 多 个 数 组 元 素 进 行 处 理, 用 指 针 方 式 访 问 元 素 比 通 过 下 标 访 问 速 度 快, 例 如 p154 例 中 的 方 法 2 8.4 指 针 运 算 指 针 之 间 有 一 些 特 定 的 运 算, 其 结 果 总 是 与 某 一 类 型 对 象 的 地 址 有 关 : (1) 两 指 针 在 一 定 条 件 下 可 以 比 较 例 如 p1,p2 指 向 同 一 数 组 中 的 元 素 (2) 与 整 型 量 可 以 进 行 加 减 运 算 p+n 表 示 指 针 p 所 指 位 置 之 后 第 n 个 对 象 的 地 址, 即 后 移 n 个 单 位 长 度 编 译 程 序 将 按 类 型 不 同 将 单 位 长 度 予 以 放 大 :char(1) short(2) int(2) long(4) float(4) double(8) 数 组 (sizeof( 数 组 )) 结 构 (sizeof( 结 构 ))
(3) 两 指 针 可 进 行 减 法, 要 求 : 指 向 同 一 数 组 中 的 元 素 p1-p2(p1>p2) 的 结 果 就 是 p1, p2 之 间 元 素 的 个 数 (4) 除 上 述 之 外, 其 它 运 算 非 法 8.5 指 针 数 组 及 其 初 始 化 当 一 数 组 中 的 元 素 为 指 针 变 量 时, 即 成 为 指 针 数 组 最 常 用 的 指 针 数 组 就 是 字 符 指 针 数 组 :char *lineptr[100]; 典 型 应 用 :p171 书 名 排 序 赋 初 值 : 类 似 前 面 的 数 组,p171,172 main() {static a[5]={1,3,5,7,9; int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]; int **p, i; p = num; for(i=0;i<5;i++) {printf( %d\t, **p); p++; p171 图 8-12: 指 针 数 组 类 似 二 维 数 组 但 有 区 别 ( 列 数 不 定 ) 按 照 C 语 言 中 指 针 和 [] 运 算 符 的 特 点, 在 使 用 时 感 觉 象 二 维 数 组 应 根 据 需 要 选 用 指 针 数 组 或 多 维 数 组 : 处 理 矩 阵, 用 多 维 数 组 方 便 ; 处 理 多 个 字 符 串, 用 指 针 数 组 方 便 8.6 命 令 行 参 数 在 操 作 系 统 中, 运 行 一 命 令 时 往 往 可 以 指 定 一 些 选 择 项, 以 便 增 强 命 令 的 灵 活 性, 如 格 式 化 命 令 拷 贝 命 令 等 用 户 所 编 程 序 经 编 译 后, 也 可 看 作 操 作 系 统 的 一 个 命 令, 有 时 也 需 具 备 上 述 功 能 可 以 将 一 个 C 程 序 中 的 main 看 作 是 操 作 系 统 所 调 用 的 函 数, 上 述 功 能 即 可 通 过 对 main 函 数 设 置 参 数 来 实 现 以 DOS/UNIX 中 的 echo 命 令 为 例, 说 明 如 何 使 用 main 的 参 数 : >echo teacher student< 回 车 > 命 令 名 选 项 1 选 项 2 C 语 言 中 main 函 数 可 以 有 两 个 参 数, 即 argc 和 argv, 其 中 argc 表 示 命 令 行 中 参 数 的 个 数,argv 是 一 个 指 针 数 组, 指 向 各 选 项 以 上 述 echo 命 令 为 例,argc 的 值 将 为 3( 包 括 命 令 名 在 内 ),argv 的 内 容 为 : echo teacher student argv[0] argv[1] argv[2] main(int argc, char *argv[]) { while(--argc>0) printf( %s%c,*++argv, (argc>1)? : \n ); main 只 能 有 上 述 这 两 个 参 数, 这 是 固 定 的, 由 于 argv 是 字 符 指 针 数 组, 所 以 当 命 令 行 选 项 是 整 型 浮 点 型 等 非 字 符 串 类 型 时, 必 须 在 程 序 中 进 行 转 换 : 例 如 需 要 实 现 下 述 的 命 令 行 选 项 : exec 5 6.3 student< 回 车 >
main(int argc, char *argv[]) { int i; float f; sscanf(argv[1], %d,&i); sscanf(argv[2], %f,&f); 内 存 格 式 转 换 函 数 : sscanf(char *, 格 式 控 制 串, 参 数 1,...) sprintf(char *, 格 式 控 制 串, 参 数 1,...) 8.7 多 级 指 针 上 述 argv, 即 字 符 指 针 数 组 就 是 多 级 指 针 的 一 种 当 指 针 所 指 内 容 又 是 指 针 时, 就 称 为 多 级 指 针 8.7.1 进 一 步 理 解 [ ] 运 算 符 char ss[10],*p; p = ss+5; 则 p[0] 等 价 于 *p 等 价 于 ss[5] p[1] 等 价 于 *(p+1) 等 价 于 ss[6] p[-1] 等 价 于 *(p-1) 等 价 于 ss[4] ss 0 1 2 3 4 5 6 7 8 9 p 8.7.2 进 一 步 理 解 二 维 数 组 与 指 针 static int a[3][4]={{1,3,5,7,{9,11,13,15,{17,19,21,23, (*p)[4]; (1) 多 维 数 组 的 地 址 谭 p179 数 组 名 a 代 表 该 数 组 的 首 址, 由 于 二 维 数 组 实 际 上 是 元 素 又 是 数 组 的 一 维 数 组, 所 以 a 指 向 其 第 0 个 元 素, 逻 辑 含 义 是 一 个 指 向 长 度 为 4 的 整 型 数 组 的 指 针 同 理 a+1 指 向 第 一 行 ;a+2 指 向 第 二 行 a[0] 可 以 理 解 为 第 0 行 的 数 组 名, 指 向 a[0][0], 所 以 逻 辑 含 义 是 一 个 指 向 int 的 指 针 ; 同 理 a[1] a[2] 分 别 是 第 1 第 2 行 的 数 组 名 所 以 :a+i 的 逻 辑 含 义 是 int (*)[4],a+i 等 价 于 &a[i]; a[i] 的 逻 辑 含 义 是 int *,a[i] 等 价 于 &a[i][0];a[i]+j 等 价 于 &a[i][j] 注 意 : 不 要 将 &a[i] 理 解 为 a[i] 单 元 的 地 址, 因 为 并 不 存 在 a[i] 这 样 一 个 变 量, 二 维 数 组 中 真 正 存 在 的 是 a[i][j], 这 只 是 一 种 计 算 地 址 的 方 法 &a[i] 和 a[i] 的 地 址 值 是 一 样 的, 但 逻 辑 含 义 不 同,&a[i] 即 a+i 指 向 第 i 行, 而 a[i] 即 *(a+i) 指 向 a[i][0] p = a; 则 :p[i] 等 价 于 *(p+i) 等 价 于 a[i] p[i][j] 等 价 于 *(*(p+i)+j) 等 价 于 *(*(a+i)+j) 等 价 于 a[i][j] (2) 二 维 数 组 作 函 数 参 数 形 参 的 定 义 方 法 :p132 或 int (*grade)[4] 8.7.3 一 个 综 合 的 例 子 char *c[] = { ENTER, NEW, POINT, FIRST ; char **cp[] = {c+3, c+2, c+1, c; char ***cpp = cp; main() { printf( %s, **++cpp); printf( %s, *--*++cpp+3); printf( %s, *cpp[-2]+3); printf( %s\n, cpp[-1][-1]+1); POINTERSTEW cpp cp c E N T E R \0 N E W \0 P O I N T \0 F I R S T \0
8.7.4 结 论 当 一 个 指 针 指 向 了 一 片 连 续 的 存 储 区 后 : (1)*p( 一 级 ): 指 向 某 数 据 类 型, 相 当 于 一 维 数 组 名 p[i] 等 价 于 *(p+i) (2)**p 或 (*p)[n]( 二 级 ): 指 向 一 级 指 针 ( 行 ), 相 当 于 二 维 数 组 名 p[i] 等 价 于 *(p+i) 一 维 p[i][j] 等 价 于 *(p+i)[j] 等 价 于 *(p[i]+j) 等 价 于 *(*(p+i)+j) (3)***p 或 (*p)[m][n]( 三 级 ): 指 向 二 级 指 针 ( 面 ), 相 当 于 三 维 数 组 名 p[i] 等 价 于 *(p+i) 二 维 p[i][j] 等 价 于 *(p+i)[j] 等 价 于 *(*(p+i)+j) 一 维 p[i][j][k] 等 价 于 *(p+i)[j][k] 等 价 于 *(*(p+i)+j)[k] 等 价 于 *(*(*(p+i)+j)+k) 总 之,( 合 法 指 针 p)[i] 等 价 于 *(p+i); 而 p+i 等 价 于 &p[i] 8.8 指 向 函 数 的 指 针 C 语 言 中, 函 数 也 可 以 通 过 指 针 间 接 调 用, 指 向 函 数 的 指 针 实 际 上 就 是 相 应 函 数 的 入 口 地 址 p177 第 9 章 引 用 引 用 与 指 针 有 关, 但 又 不 相 同 它 是 C++ 中 新 增 的, 主 要 目 的 是 为 了 更 加 方 便 对 函 数 参 数 的 传 递 9.1 什 么 是 引 用 引 用 实 际 上 就 是 为 某 个 变 量 或 对 象 所 建 立 的 别 名, 对 引 用 的 修 改 实 际 上 就 是 对 相 应 变 量 或 对 象 的 修 改 int someint; int&rint=someint; 在 声 明 时 必 须 初 始 化 p185 例 ch9-1.cpp 注 意 :(1) 若 引 用 被 声 明 为 T&, 则 必 须 用 T 类 型 的 变 量 或 对 象, 或 能 够 转 换 成 T 类 型 的 对 象 进 行 初 始 化 (2) 若 声 明 引 用 时 所 用 的 初 始 值 不 是 左 值, 则 会 建 立 一 个 T 类 型 的 变 量 并 用 该 初 始 值 对 其 初 始 化, 引 用 即 和 所 建 立 的 变 量 相 关 联 p188 (3) 允 许 建 立 对 指 针 变 量 的 引 用 int *a; int * &p=a; int b=8; p=&b; *p=10; (4) 不 允 许 对 void 进 行 引 用 (5) 不 能 建 立 引 用 的 数 组, 也 不 能 为 数 组 名 建 立 引 用, 因 为 数 组 名 不 是 变 量 (6) 引 用 只 是 某 个 变 量 的 别 名, 本 身 不 是 变 量, 所 以 没 有 引 用 的 引 用, 也 没 有 引 用 的 指 针 (7) 有 空 指 针, 无 空 引 用 int &ri = NULL; 非 法 9.2 引 用 的 操 作 (1) 取 引 用 的 地 址, 得 到 的 将 是 其 相 关 变 量 的 地 址 p186 (2) 对 引 用 的 任 何 赋 值, 实 际 上 都 是 对 其 相 关 变 量 的 赋 值 p187 (3) 引 用 一 旦 初 始 化, 就 关 联 到 一 个 固 定 的 变 量 上, 再 也 不 分 开, 不 能 象 指 针 那 样 通 过 复 写 操 作 指 向 另 一 个 对 象 9.3 用 引 用 传 递 函 数 参 数 用 引 用 做 函 数 形 参 可 以 实 现 在 函 数 体 内 改 变 对 应 实 参 值 的 目 的, 其 效 果 与 使 用 指 针 完 全 相 同, 但 使 用 时 更 加 简 单 (p190) 这 实 际 上 相 当 与 PASCAL 中 参 数 的 传 地 址 方 式
注 意 : 用 引 用 传 递 函 数 参 数 时, 注 意 可 能 带 来 的 二 义 性 p191 9.4 用 引 用 返 回 函 数 值 C++ 允 许 函 数 的 返 回 值 为 引 用, 注 意 p193 有 关 引 用 返 回 的 4 种 不 同 情 况 要 特 别 注 意 不 要 返 回 一 个 对 局 部 变 量 的 引 用 9.5 用 const 限 定 引 用 使 用 指 针 或 引 用 作 为 函 数 参 数 的 好 处 主 要 是 : (1) 使 函 数 可 以 传 回 多 个 值 (2) 提 高 效 率 但 是 也 有 缺 点 : 这 会 使 实 参 对 应 的 变 量 处 于 随 时 会 被 修 改 的 危 险 之 中 有 时 只 需 要 使 用 引 用 提 高 效 率, 但 不 希 望 实 参 被 函 数 修 改, 这 时 就 可 以 用 const 指 针 或 引 用 对 实 参 加 以 保 护 p198 第 10 章 结 构 和 联 合 10.1 结 构 类 型 的 定 义 和 数 组 一 样, 结 构 也 是 一 种 组 合 数 据 类 型 与 数 组 不 同 的 是 : 数 组 是 由 一 组 相 同 类 型 的 数 据 组 成 的 ; 而 结 构 则 是 有 一 组 不 同 类 型 的 数 据 所 组 成 的 在 实 际 应 用 中, 有 很 多 数 据 信 息 必 须 用 结 构 来 表 示, 例 如 人 事 记 录 课 程 信 息 等 p204 例 说 明 其 必 要 性 (1) 定 义 :struct 结 构 类 型 标 识 符 { 成 员 1; // 可 以 是 基 本 数 据 类 型 成 员 2; 数 组 或 另 一 个 结 构 等 [ 结 构 变 量 名 ]; 例 :struct date { int day, month, year; char mon_name[10]; d1, d2; struct date d3; (2) 初 值 : 类 似 数 组 赋 初 值 的 方 式 : static struct date d1 = {12, 5, 1990, MAY ; (3) 对 成 员 的 访 问 : 可 以 有 三 种 方 式 a. 结 构 变 量 名. b. 结 构 指 针 名 -> 结 构 成 员 c. (* 结 构 指 针 ). 例 :struct date d, *pd; pd = &d; d.day = 12; pd->month = 5; (*pd).mon_name = MAY ; 10.2 结 构 和 函 数 主 要 解 决 的 是 结 构 变 量 作 为 函 数 参 数 传 递 的 情 况 由 于 C 支 持 对 结 构 变 量 的 整 体 赋 值 (p206), 所 以 作 为 函 数 参 数 可 以 有 两 种 用 法 :(1) 形 参 为 结 构 变 量, 此 时 形 实 参 整 体 赋 值 (2) 形 参 为 结 构 指 针 或 引 用 p212~213
函 数 的 返 回 值 也 可 以 是 结 构 结 构 指 针 结 构 引 用 结 构 除 了 它 是 由 用 户 定 义 的 组 合 数 据 类 型 之 外, 其 它 方 面 与 基 本 数 据 类 型 完 全 类 似 10.3 结 构 数 组 当 一 个 数 组 的 每 个 元 素 都 是 结 构 时, 就 称 为 结 构 数 组, 经 常 用 它 来 处 理 一 系 列 的 记 录 如 p210 例 10_5.cpp 所 示 的 关 于 6 个 人 的 薪 水 情 况 的 记 录 例 10_6.cpp 利 用 结 构 指 针 数 组 提 高 效 率 经 验 : 应 用 中 常 会 遇 到 这 样 的 情 况 : (1) 该 问 题 适 合 用 数 组 解 决 (2) 数 组 的 长 度 事 先 不 好 确 定 这 时 希 望 能 定 义 长 度 可 变 的 数 组, 而 C 语 言 在 定 义 数 组 时, 要 求 长 度 必 须 是 常 量, 所 以 不 能 用 C 本 身 的 数 组 定 义 实 现 上 述 目 的 但 是 由 于 C 的 指 针 与 数 组 间 的 特 殊 关 系, 所 以 利 用 指 针 和 动 态 申 请 内 存 的 库 函 数 malloc( ) 便 可 实 现 上 述 目 的 p155 以 例 ch10_5.cpp 中 的 结 构 数 组 为 例, 定 义 结 构 指 针 per: #include<alloc.h> //void *malloc(size_t size) struct person *per; int num; // 确 定 数 组 长 度 scanf( %d,&num); per = (struct person *)malloc(sizeof(struct person)*num); per[1].name = John ; per[1].id = 13916; // 此 后 便 可 将 per 当 成 长 度 为 num 的 数 组 来 用 [0] [1] [2] [3]...... [num-1] per sizeof(struct person) 个 字 节 sizeof(struct person) * num 个 字 节 总 之, 在 C 语 言 中, 只 要 一 个 指 针 指 向 了 一 片 连 续 的 存 储 区, 即 可 将 将 它 作 为 数 组, 连 续 的 存 储 区 既 可 通 过 数 组 定 义 静 态 获 得, 也 可 通 过 malloc 或 new 动 态 获 得 10.4 指 向 结 构 的 指 针 ( 结 构 指 针 ) 即 一 个 结 构 变 量 的 首 地 址, 结 构 指 针 的 主 要 用 途 有 三 : (1)10.2 所 述, 用 作 函 数 参 数 (2)10.3 所 述, 结 合 结 构 数 组, 引 用 其 元 素 ; 或 构 造 动 态 结 构 数 组 注 意 其 单 位 长 度 是 sizeof(struct......),c 采 用 偶 地 址 分 配 (3) 下 节 所 述, 用 于 构 造 链 表 树 等 数 据 结 构 10.5 树 和 表 树 和 表 都 是 重 要 且 很 常 用 的 数 据 结 构, 在 数 据 结 构 课 中 将 会 详 细 介 绍, 为 说 明 结 构 指 针 的 用 法, 此 处 简 单 介 绍 链 表 结 构 10.5.1 什 么 是 链 表
(1) 引 用 自 身 的 结 构 : 结 构 允 许 嵌 套 定 义, 即 结 构 的 一 个 成 员 是 另 外 一 种 结 构, 但 不 能 是 该 结 构 自 身 ; 不 过 可 以 是 指 向 自 身 的 指 针 p217 (2) 多 个 结 构 变 量 的 组 织 : 程 序 中 经 常 需 要 同 时 处 理 多 个 结 构 相 同 的 结 构 变 量 ( 如 某 单 位 的 人 事 信 息 ), 这 些 结 构 变 量 的 组 织 方 式 如 下 : a. 事 先 已 知 结 构 的 个 数, 且 程 序 运 行 过 程 中 不 变 : 用 结 构 数 组 b. 程 序 运 行 后 才 知 结 构 个 数, 且 不 再 变 化 : 用 动 态 结 构 数 组 ( 结 构 指 针 +malloc) c. 自 始 至 终 也 不 知 究 竟 会 有 多 少 个 结 构, 或 者 在 程 序 运 行 中 个 数 会 不 停 变 化, 此 时 结 构 随 机 散 布 在 内 存 中, 不 是 连 续 存 放 的 : 用 链 表 或 树 等 数 据 结 构 (3) 链 表 结 构 : 对 于 上 述 第 三 种 应 用 情 况, 用 引 用 自 身 的 结 构 将 多 个 结 构 串 接 起 来, 即 构 成 链 表 结 构 p219 图 10-2 10.5.2 链 表 的 创 建 与 遍 历 p219 例 ch10-11.cpp, 构 造 并 显 示 学 生 成 绩 信 息 注 意 :C 语 言 中 没 有 new 操 作 符, 申 请 新 结 点 要 自 编 一 个 函 数 : struct student * getnode() { return((struct student *)malloc(sizeof(struct student))); 10.6.3 链 表 的 插 入 与 删 除 p222 例, 图 10-3 图 10-4 p224 例, 图 10-5 注 意 对 链 表 的 头 尾 的 处 理, 是 最 容 易 出 错 的 地 方 p225 10.7 字 段 存 取 节 省 空 间 的 一 种 方 法, 允 许 将 若 干 个 状 态 量 压 缩 到 一 个 机 器 字 中 其 功 能 完 全 可 以 用 字 位 逻 辑 运 算 来 实 现, 但 用 字 段 存 取 更 方 便 例 如 结 构 date 也 可 以 用 字 段 来 表 示 : struct date { char flag; // 闰 年 int day, month; ; struct date1 { unsigned int flag:1; unsigned int day: 5; unsigned int month:4; d1; 10.8 联 合 类 型 节 省 空 间 的 另 一 种 方 法, 定 义 类 似 于 结 构 可 将 其 想 象 成 结 构, 但 所 占 空 间 不 是 各 成 员 的 总 和, 而 是 各 成 员 中 所 占 空 间 最 大 者, 所 以 也 称 为 共 用 体 union v_tag { int ival; float fval; char *pval; uval, *p; uval.ival = 5;...... p = &uval; p->fval = 6.3...... 10.9 类 型 定 义 C 允 许 用 户 用 typedef 定 义 数 据 类 型, 例 如 : typedef int INTEGER; INTEGER i; typedef struct date { int day, month, year; char mon_name[10]; DATE; DATE d1, d2, *pd;
目 的 : 方 便 编 程, 特 别 对 一 些 复 杂 的 定 义, 用 typedef 定 义 成 一 个 新 的 类 型, 免 得 每 次 都 写 一 大 串 : typedef int (*(*(*POINTFUNC( ) )[ ] )( ) )[ ]; POINTFUNC check1, check2; 用 途 :(1) 便 于 程 序 移 植, 将 与 硬 件 有 关 的 数 据 类 型 用 typedef 重 新 定 义 (2) 使 程 序 清 晰, 易 于 理 解 第 11 章 C 预 处 理 程 序 C 的 特 色 之 一 通 过 预 处 理 有 效 地 扩 充 语 言 的 能 力, 使 程 序 易 于 开 发 阅 读 修 改 及 移 植 11.1 #define 语 句 定 义 符 号 常 数 及 宏 11.1.1 定 义 符 号 常 数 格 式 :#define 符 号 常 数 标 识 符 单 词 串 标 志 如 : #define TRUE 1 #define FALSE 0 注 意 :(1) 该 语 句 后 不 可 用 分 号 (2) 不 一 定 非 在 程 序 头 上, 可 在 任 何 地 方 出 现, 但 名 必 须 先 定 义, 然 后 才 可 用 不 存 在 所 谓 局 部 的 问 题 好 处 :(1) 程 序 的 可 扩 展 性, 易 读 易 改 : #define MAXSIZE 100 char *sp[maxsize];...... for(i=0; i<maxsize; i++)...... (2) 增 强 可 移 植 性 : #define INT_SIZE 16 //machine dependent 11.1.2 宏 定 义 及 展 开 即 在 #define 中 带 变 元 的 情 况, 称 为 宏 定 义 (macro) #define max(a,b) ((a)>(b)?(a):(b)) 将 来 在 程 序 中, 语 句 x = max(p+g, r+s); 将 被 替 换 为 : x = ((p+q)>(r+s)?(p+q):(r+s)); 注 意 : 宏 定 义 会 产 生 副 作 用, 例 如 : #define SQUARE(x) x*x 则 y = SQUARE(v); y = v*v; 而 y = SQUARE(p+q); y = p+q*p+q; //error 所 以 必 须 注 意 定 义 严 格 : #define SQUARE(x) (x)*(x) 小 结 :(1) 宏 在 使 用 时 类 似 函 数, 但 与 函 数 不 同, 它 不 安 全, 但 运 行 效 率 高 功 能 上 相 当 于 C++ 中 的 inline 函 数 (2) 长 的 定 义, 如 需 分 多 行, 行 间 用 \ 分 隔 (3) 可 重 复 定 义, 使 用 时 以 前 面 最 近 一 次 定 义 为 准 (4) 可 嵌 套 定 义 :#define OK 1 #define GOOD OK (5) 可 撤 消 定 义 :#undef OK
11.2 #include 语 句 C 可 用 include 语 句 将 另 一 个 文 件 蕴 含 到 当 前 源 文 件 中 比 如 定 义 了 多 个 符 号 常 数 和 宏, 且 它 们 在 多 个 程 序 程 序 中 都 要 用 到, 这 时 可 将 它 们 收 集 起 来 存 入 一 个 文 件, 如 constant.h ( 一 般 以.h 为 后 缀, 取 header 之 意 ), 在 使 用 它 的 源 文 件 头 上 : #include constant.h #include <stdio.h> // 注 意 与 用 法 的 区 别, 查 找 快 优 点 : 能 将 定 义 集 中 起 来, 供 多 个 程 序 共 同 使 用 在 大 程 序 中, 易 于 修 改, 避 免 产 生 定 义 的 不 一 致 11.3 条 件 编 译 可 在 程 序 中 设 置 一 些 编 译 开 关, 对 程 序 中 的 某 些 语 句 有 选 择 地 编 译 (1)#ifdef, #endif, #else 和 #ifndef 语 句 判 断 某 个 符 号 常 数 是 否 用 #define 定 义 过, 以 决 定 是 否 对 其 后 的 语 句 进 行 编 译 用 途 一 : 增 强 程 序 的 可 移 植 性 例 如,C 语 言 在 不 同 机 器 上 int 类 型 的 长 度 不 同, 则 编 程 时 可 以 : #ifdef PDP11 #define INT_SIZE 16 //PDP11 上 整 型 占 2 个 字 节 #else #define INT_SIZE 32 // 其 它 机 器 上 整 型 占 4 个 字 节 #endif 用 户 可 根 据 情 况 选 择 是 否 要 定 义 PDP11, 为 给 PDP11 加 定 义 : a. 在 程 序 前 加 上 :#define PDP11 1 甚 至 #define PDP11 即 可 b. 用 编 译 命 令 的 命 令 行 参 数 ( 以 UNIX 为 例 ): cc my_prog.c -D PDP11< 回 车 > 用 途 二 : 在 调 试 程 序 时, 作 为 跟 踪 语 句 的 开 关 : #ifdef DEBUG printf( ***Test information\n );...... #endif 调 试 时 用 -D 编 译, 成 功 后 不 用, 目 标 代 码 中 便 可 去 除 跟 踪 信 息 (2)#if 语 句 它 通 过 了 更 一 般 的 方 法, 可 针 对 符 号 常 数 的 值 进 行 多 种 选 择 : #if MACHINE==1...... #else #if MACHINE==2...... #else #if MACHINE==3...... #endif #endif #endif 为 符 号 常 数 赋 值 : a. #define MACHINE 1( 或 2,3) b. 编 译 命 令 行 参 数 : cc my_prog.c -D MACHINE=2< 回 车 > 第 12 章 操 作 系 统 上 的 C 程 序 实 际 上 就 是 由 各 库 函 数 构 成 的 一 个 编 程 环 境
12.1 标 准 文 件 的 输 入 / 输 出 处 理 操 作 系 统 将 I /O 设 备 也 作 为 文 件 处 理, 任 何 C 程 序 都 包 含 三 个 标 准 文 件 : 标 准 输 入 文 件 stdin, 标 准 输 出 文 件 stdout, 标 准 出 错 文 件 stderr (1)scanf 等 : 从 stdin 输 入 数 据 (2)printf 等 : 向 stdout 输 出 数 据 12.2 文 件 输 入 / 输 出 (1) 将 I / O 重 定 向 到 文 件 a. 输 出 重 定 向 (>):my_exec > ttt.dat< 回 车 > 会 将 原 输 出 到 stdout 的 内 容 全 部 输 出 到 文 件 ttt.dat 中 b. 输 入 重 定 向 (<):my_exec < input.dat< 回 车 > 会 将 stdin 重 定 向 到 文 件 input.dat, 改 从 该 文 件 中 输 入 数 据 (2) 关 于 文 件 结 束 大 多 数 库 函 数, 在 遇 到 文 件 结 束 时 会 返 回 标 志 EOF, 在 程 序 中 应 判 断 此 标 志, 否 则 可 能 陷 于 死 循 环 例 如 程 序 : #include<stdio.h> main() {int c; while((c = getchar())!= EOF) putchar(c); 假 定 编 译 后 的 可 执 行 文 件 名 为 exec.exe, 则 exec < infile.txt< 回 车 > 的 效 果 是 在 屏 幕 上 将 文 件 infile.txt 的 内 容 打 印 出 来 12.3 用 于 文 件 处 理 的 特 殊 函 数 对 文 件 的 简 单 处 理 用 scanf printf putchar getchar 等 函 数 加 上 I /O 重 定 向 即 可 解 决 但 有 时 需 要 更 大 的 灵 活 性 对 文 件 进 行 复 杂 的 操 作, 比 如 从 两 个 文 件 中 同 时 读 数 据, 这 时 就 需 要 下 述 的 文 件 处 理 函 数 : (1)fopen 函 数 FILE *fp, *fopen(); fp = fopen( 文 件 名, r ); // 或 者 w 写 a 添 加 (2)getc 和 putc 函 数 char c; c = getc(fp); putc( \n, fp); (3)fclose 函 数 fclose(fp); 文 件 操 作 全 部 完 成 后 将 文 件 关 闭 (4)feof 函 数 判 断 是 否 已 读 取 到 文 件 尾 ( 结 束 返 回 1, 否 则 返 回 0): if(feof(fp) printf( Run out of data!\n ); (5)fscanf 和 fprintf 对 文 件 按 格 式 输 入 / 输 出 :fscanf(fp, 格 式 控 制 串, 参 数 1, 参 数 2...) (6)fgets 和 fputs fgets(char *buffer, n, fp); 直 到 读 到 \n 或 读 满 n 个 字 符 为 止, 读 出 的 内 容 存 入 buffer, 最 后 自 动 加 \0 fputs(char *buffer, fp); 将 buffer 中 的 内 容 写 入 文 件, 直 到 写 到 \0 为 止, 但 \0 不 写 入 文 件
(7)fread 和 fwrite int fread(char *pt, unsigned size, unsigned n, FILE *fp) 从 fp 所 指 文 件 中 读 取 长 度 为 size 的 n 个 数 据 项, 存 到 pt 所 指 的 内 存 区 返 回 所 读 数 据 项 的 个 数, 如 遇 文 件 结 束 或 出 错 返 回 0 int fwrite(char *pt, unsigned size, unsigned n, FILE *fp) 将 pt 所 指 的 n*size 个 字 节 输 出 到 fp 所 指 的 文 件 中 返 回 所 写 数 据 项 的 个 数 例 :struct student { char name[10]; int age; char addr[30]; stud[40]; 则 用 fwrite(stud, sizeof(struct student), 40, fp); 即 可 将 该 结 构 数 组 写 入 fp 所 指 的 文 件 中 将 来 用 fread(stud, sizeof(struct student), 40, fp); 又 可 从 文 件 中 将 该 数 组 读 出 来 第 13 章 类 和 面 向 对 象 程 序 设 计 13.1 类 的 定 义 类 是 面 向 对 象 程 序 设 计 的 基 础, 通 过 类, 实 现 数 据 及 对 其 进 行 处 理 的 函 数 ( 方 法 ) 的 封 装, 从 而 实 现 信 息 隐 藏, 屏 蔽 细 节, 提 高 程 序 的 可 重 用 性, 提 高 程 序 设 计 的 效 率 C++ 的 类 由 C 的 结 构 发 展 而 来 : (1) p232 C 中 表 示 存 款 帐 户 的 结 构 Savings (2) p233 C++ 中 表 示 存 款 帐 户 的 类 Savings, 注 意 除 了 数 据 成 员 外 还 有 方 法 说 明 类 具 有 封 装 性, 必 须 通 过 方 法 才 能 修 改 保 护 成 员 的 值 (3) 类 与 结 构 的 区 别 p233 13.2 面 向 对 象 程 序 设 计 13.2.1 为 什 么 要 引 入 类 这 是 程 序 开 发 方 法 发 展 的 必 然 80 年 代 中 开 始 出 现 的 软 件 危 机 使 得 传 统 的 程 序 设 计 方 法 面 临 挑 战 早 期 的 结 构 化 设 计 方 法 : 程 序 =( 算 法 )+( 数 据 结 构 ), 以 算 法 ( 过 程 ) 为 主, 见 p234 图 11-1 缺 点 : 不 利 于 软 件 的 重 用, 开 发 过 程 复 杂, 效 率 低 面 向 对 象 的 设 计 方 法 : 数 据 结 构 及 其 相 关 的 算 法 被 封 装 成 一 个 类, 对 象 是 类 的 一 个 实 例, 这 时 : 对 象 = ( 算 法 + 数 据 结 构 ) 程 序 = ( 对 象 + 对 象 +...) 优 点 : 大 大 提 高 了 程 序 的 可 重 用 性, 简 化 了 程 序 设 计, 提 高 开 发 效 率 对 象 成 为 程 序 的 基 本 构 件, 编 程 就 好 象 在 搭 积 木 + + 结 构 化 程 序 设 计 : 定 制 构 件 面 向 对 象 程 序 设 计 : 利 用 已 有 标 准 件 搭 积 木
由 于 突 破 了 软 件 设 计 思 想 上 的 障 碍, 软 件 产 业 得 以 飞 速 发 展 C++ 是 类 机 制 实 现 得 比 较 完 善 的 一 种 高 级 语 言 13.2.2 抽 象 抽 象 就 是 具 体 事 物 的 描 述 的 一 个 概 括, 以 隐 藏 事 物 固 有 的 复 杂 性 将 现 实 世 界 中 的 事 物 抽 象 成 对 象, 以 便 编 程 即 忽 略 细 节, 只 知 接 口 P299, 将 Josephus 问 题 抽 象 成 两 个 类 :Josephus 类 和 Ring 类 13.2.3 分 类 将 具 有 某 些 共 性 的 对 象 按 一 定 规 则 归 为 一 类, 层 层 分 类, 使 概 念 逐 渐 细 化, 构 成 类 树 : 人 教 职 工 学 生 职 员 教 师 工 人 研 究 生 本 科 生 讲 师 助 教 教 授 在 职 研 究 生 其 中 子 类 可 以 继 承 父 类 的 所 有 属 性 和 方 法 继 承 使 得 程 序 具 有 较 高 的 可 重 用 性, 可 以 提 高 开 发 效 率 总 之 : 结 构 化 程 序 设 计 : 按 功 能 分 割 问 题, 强 调 的 是 处 理 过 程 的 功 能 划 分, 每 个 功 能 都 靠 自 己 解 决 如 果 一 个 功 能 与 另 一 个 已 有 功 能 的 实 现 类 似, 也 不 能 直 接 为 我 所 用 面 向 对 象 程 序 设 计 : 以 数 据 为 中 心, 按 对 象 分 割 问 题 对 象 被 分 成 类, 类 又 是 层 层 分 解 的, 子 类 可 以 继 承 父 类 的 所 有 特 性 和 行 为, 同 样 的 对 象 可 直 接 用 于 多 个 不 同 的 程 序 P293~310 对 Josephus 问 题 的 解 答, 注 意 体 会 结 构 化 程 序 设 计 与 面 向 对 象 程 序 设 计 的 本 质 区 别 13.3 定 义 成 员 函 数 即 对 象 的 方 法 定 义 方 法 与 前 面 的 函 数 基 本 相 同, 只 不 过 是 在 类 中 定 义 的 P236 (1) 在 类 定 义 中 定 义 成 员 函 数 (inline) (2) 在 类 定 义 之 后 定 义 成 员 函 数 P238, 这 是 典 型 的 OO 程 序 的 写 法 (3) 重 载 成 员 函 数 P239 13.4 调 用 成 员 函 数 (1) 调 用 : 成 员 函 数 必 须 通 过 对 象 来 调 用, 其 形 式 类 似 于 访 问 结 构 的 一 个 成 员, 除 此 以 外 与 调 用 普 通 函 数 完 全 相 同 P240~241 (2) 在 成 员 函 数 中 访 问 成 员 ( 属 性 ):p243 13.5 保 护 成 员 对 某 些 成 员 加 以 保 护 不 允 许 从 外 部 直 接 访 问, 只 能 通 过 接 口 访 问, 这 也 是 封 装 的 特 性 之 一 13.6 屏 蔽 类 的 内 部 实 现 类 实 现 了 对 数 据 及 其 行 为 的 封 装, 要 使 用 某 个 类, 只 要 了 解 它 的 公 共 成 员 即 可 ( 接 口 ), 即 使 类 的 内 部 实 现 完 全 改 变 了, 但 只 要 接 口 不 变, 该 类 的 使 用 方 法 就 不 会 变 P247~251
13.7 再 论 程 序 结 构 p252 13.8 关 于 构 造 函 数 和 析 构 函 数 构 造 函 数 和 析 构 函 数 是 类 的 特 殊 成 员 函 数 构 造 函 数 创 建 对 象, 并 初 始 化 其 成 员 ; 析 构 函 数 负 责 撤 销 对 象 时 的 善 后 工 作 构 造 函 数 在 创 建 对 象 时 被 自 动 调 用, 如 果 没 有 专 门 定 义 构 造 函 数 则 调 用 缺 省 的 构 造 函 数 见 p263 例 析 构 函 数 在 对 象 被 撤 销 时 被 自 动 调 用, 它 没 有 返 回 值, 没 有 参 数, 不 能 重 载 见 p269 例 13.9 关 于 堆 (1) 关 于 堆 区 P312 (2)malloc / free 和 new / delete 的 区 别 在 不 使 用 类 时, 两 者 在 功 能 上 是 等 价 的 ( 见 p158): int *p = new int; 等 价 于 int *p = (int *)malloc(sizeof(int)); 但 在 创 建 对 象 时,new 和 malloc 是 有 区 别 的 见 p313 第 14 章 I/O 流 14.1 printf 和 scanf 的 缺 陷 P415 14.2 I / O 标 准 流 类 P416 14.3 文 件 流 类 P418 14.4 串 流 类 P420 14.5 控 制 符 用 于 控 制 输 出 的 格 式 P421~424