第 六 讲 指 针 与 字 符 串 1
内 容 提 要 指 针 持 久 动 态 内 存 分 配 字 符 串 ( 字 符 数 组 ) 2
指 针 什 么 是 指 针 指 针 的 定 义 与 运 算 指 针 与 一 维 数 组 指 针 数 组 行 指 针 与 二 维 数 组 指 针 与 引 用 指 针 与 函 数 3
指 针 定 义 什 么 是 指 针 指 针 变 量, 简 称 指 针, 用 来 存 放 其 它 变 量 的 内 存 地 址 指 针 的 定 义 类 型 标 识 符 * 指 针 变 量 名 声 明 一 个 指 针 类 型 的 变 量, 星 号 后 面 可 以 留 空 格 类 型 标 识 符 表 示 该 指 针 所 指 向 的 对 象 的 数 据 类 型, 即 该 指 针 所 代 表 的 内 存 单 元 所 能 存 放 的 数 据 的 类 型 Tips: 变 量 为 什 么 要 声 明? 1) 分 配 内 存 空 间 ; 2) 限 定 变 量 能 参 与 的 运 算 及 运 算 规 则 Tips: 内 存 空 间 的 访 问 方 式 :1) 变 量 名 ; 2) 内 存 地 址, 即 指 针 4
指 针 运 算 指 针 的 两 个 基 本 运 算 提 取 变 量 的 内 存 地 址 :& 提 取 指 针 所 指 向 的 变 量 的 值 :* 地 址 运 算 符 :& & 变 量 名 // 提 取 变 量 在 内 存 中 的 存 放 地 址 例 : int x=3; int * px; // 定 义 指 针 px px=&x; // 将 x 的 地 址 赋 给 指 针 px 此 时, 我 们 通 常 称 这 里 的 px 是 指 向 x 的 指 针 注 意 : 指 针 的 类 型 必 须 与 其 指 向 的 对 象 的 类 型 一 致 5
指 针 运 算 指 针 运 算 符 : * * 指 针 变 量 名 // 提 取 指 针 变 量 所 指 向 的 对 象 的 值 例 : int x; int * px; // 声 明 指 针 变 量, 星 号 后 面 可 以 有 空 格! px=&x; *px = 3; // 等 价 于 x = 3, 星 号 后 面 不 能 有 空 格! ex06_pointer_01.cpp 在 使 用 指 针 时, 我 们 通 常 关 心 的 是 指 针 指 向 的 元 素! 初 始 化 : 声 明 指 针 变 量 时, 可 以 赋 初 值 例 : int x = 3; int * px = &x; // 指 针 的 值 只 能 是 某 个 变 量 的 地 址 6
空 指 针 void 类 型 的 指 针 void * 指 针 名 void 类 型 的 指 针 可 以 指 向 任 何 类 型 的 对 象 的 地 址 不 允 许 使 用 void 指 针 操 纵 它 所 指 向 的 对 象! 通 过 显 式 类 型 转 换, 可 以 访 问 void 类 型 指 针 所 指 向 的 对 象 例 : int x = 3; int * px; void * pv; pv = &x; // OK, void 型 指 针 指 向 整 型 变 量 px = (int *)pv; // OK, 使 用 void 型 指 针 时 需 要 强 制 类 型 转 换 7
指 针 赋 值 指 针 可 能 的 取 值 一 个 有 效 的 指 针 只 有 三 种 取 值 : (1) 一 个 对 象 的 地 址 ; (2) 指 向 某 个 对 象 后 面 的 对 象 ; (3) 值 为 0 或 NULL( 空 指 针 ) int x=3; int * px=&x; int * py=&x+1; int * pi; pi=0; // OK pi=null; // OK 没 有 初 始 化 或 赋 值 的 指 针 是 无 效 的 指 针, 引 用 无 效 指 针 会 带 来 难 以 预 料 的 问 题! 指 针 赋 值 : 只 能 使 用 以 下 四 种 类 型 的 值 (1) 0 或 者 值 为 0 的 常 量, 表 示 空 指 针 ; (2) 类 型 匹 配 的 对 象 的 地 址 ; (3) 同 类 型 的 另 一 有 效 指 针 ; (4) 另 一 个 对 象 的 下 一 个 地 址 8
指 针 与 常 量 指 向 常 量 的 指 针 const 类 型 标 识 符 * 指 针 名 const int a = 3; int * pa = &a; // ERROR const int * cpa = &a; // OK 指 向 const 对 象 ( 常 量 ) 的 指 针 必 须 用 const 声 明! 这 里 的 const 限 定 了 指 针 所 指 对 象 的 属 性, 不 是 指 针 本 身 的 属 性! const int a = 3; int b = 5; const int * cpa = &a; // OK *cpa = 5; // ERROR cpa = &b; // OK *cpa = 9; // ERROR b = 9; // OK ex06_pointer_02.cpp 指 向 const 的 指 针 所 指 对 象 的 值 并 不 一 定 不 能 修 改! 允 许 把 非 const 对 象 的 地 址 赋 给 指 向 const 的 指 针 ; 但 不 允 许 使 用 指 向 const 的 指 针 来 修 改 它 所 指 向 的 对 象 的 值! 9
指 针 与 常 量 常 量 指 针, 简 称 常 指 针 常 量 指 针 : 指 针 本 身 的 值 不 能 修 改 类 型 标 识 符 * const 指 针 名 int a = 3, b = 5; int * const pa = &a; // OK pa = &b; // ERROR 指 向 const 对 象 的 const 指 针 const 类 型 标 识 符 * const 指 针 名 指 针 本 身 的 值 不 能 修 改, 其 指 向 的 对 象 的 值 也 不 能 修 改 10
指 针 算 术 运 算 指 针 可 以 和 整 数 或 整 型 变 量 进 行 加 减 运 算, 且 运 算 规 则 与 指 针 的 类 型 相 关! int * pa; int k; pa + k --> pa 所 指 的 当 前 位 置 之 后 第 k 个 元 素 的 地 址 pa - k --> pa 所 指 的 当 前 位 置 之 前 第 k 个 元 素 的 地 址 在 指 针 上 加 上 或 减 去 一 个 整 型 数 值 k, 等 效 于 获 得 一 个 新 指 针, 该 指 针 指 向 原 来 的 元 素 之 后 或 之 前 的 第 k 个 元 素 指 针 的 算 术 运 算 通 常 是 与 数 组 的 使 用 相 联 系 的 一 个 指 针 可 以 加 上 或 减 去 0, 其 值 不 变 int * pa; int k; pa++ --> pa 所 指 的 当 前 位 置 之 后 的 元 素 的 地 址 pa-- --> pa 所 指 的 当 前 位 置 之 前 的 元 素 的 地 址 11
指 针 算 术 运 算 short * pa // 每 个 元 素 占 两 个 字 节 pa-2 pa-1 pa pa+1 pa+2 pa+3 *(pa-2) *(pa-1) *pa *(pa+1) *(pa+2) *(pa+3) 12
指 针 算 术 运 算 int * pb // 每 个 元 素 占 四 个 字 节 pb-1 pb *(pb-1) *pb pb+1 pb+2 *(pb+1) *(pb+2) 13
指 针 与 数 组 C++ 中, 指 针 与 数 组 密 切 相 关 : 由 于 数 组 元 素 在 内 存 中 是 连 续 存 放 的, 因 此 使 用 指 针 可 以 非 常 方 便 地 处 理 数 组 元 素! int a[]={0,2,4,8}; int * pa; pa = a; // OK pa = &a[0]; // OK, 与 上 式 等 价 *pa = 3;// OK, 等 价 于 a[0]=3 *(pa+2) = 5; // OK, 等 价 于 a[2]=5 *(a+2) = 5; // OK, 等 价 于 a[2]=5 在 C++ 中, 数 组 名 就 是 数 组 的 首 地 址! 当 数 组 名 出 现 在 表 达 式 中 时, 会 自 动 转 化 成 指 向 第 一 个 数 组 元 素 的 指 针! 思 考 :pa = a+1, 则 *pa =? 14
一 维 数 组 与 指 针 一 维 数 组 与 指 针 在 C++ 中, 引 用 数 组 元 素 有 以 下 三 种 方 式 : (1) 数 组 名 与 下 标, 如 :a[0] (2) 数 组 名 与 指 针 运 算, 如 :*(a+1) (3) 指 针, 如 :int * pa=a; *pa int a[]={0,2,4,8}; int * pa = a; *pa = 1; // 等 价 于 a[0]=1 ex06_pointer_03.cpp *(pa+2) = 5; // 等 价 于 a[2]=5 *(a+2) = 5; // OK, 等 价 于 a[2]=5 *(pa++) = 3; // OK, 等 价 于 a[0]=3; pa = pa+1; *(a++) = 3; // ERROR! a 代 表 数 组 首 地 址, 是 常 量 指 针! *(pa+1) = 10; // 思 考 : 修 改 了 哪 个 元 素 的 值? 指 针 的 值 可 以 随 时 改 变, 即 可 以 指 向 不 同 的 元 素 ; 数 组 名 是 常 量 指 针, 值 不 能 改 变 15
举 例 例 : 使 用 三 种 方 法 输 出 一 个 数 组 的 所 有 元 素 // 第 一 种 方 式 : 数 组 名 与 下 标 for (int i=0; i<n; i++) cout << a[i] << "," ; // 第 二 种 方 式 : 数 组 名 与 指 针 运 算 for (int i=0; i<n; i++) cout << *(a+i) << "," ; // 第 三 种 方 式 : 指 针 for (int * pa=a; pa<a+n; pa++) cout << *pa << "," ; // 第 三 种 方 式 : 指 针 for (int * pa=a, i=0; i<n; i++) cout << pa[i] << "," ; 若 pa 是 指 针,k 是 整 型 数 值, 则 *(pa+k) 可 以 写 成 pa[k] *(pa-k) 可 以 写 成 pa[-k] ex06_pointer_04.cpp 16
一 维 数 组 与 指 针 一 维 数 组 a[n] 与 指 针 pa=a 数 组 名 a 是 地 址 常 量, 数 组 名 a 与 &a[0] 等 价 ; a+i 是 a[i] 的 地 址,a[i] 与 *(a+i) 等 价 ; 数 组 元 素 的 下 标 访 问 方 式 也 是 按 地 址 进 行 的 ; 可 以 通 过 指 针 pa 访 问 数 组 的 任 何 元 素, 且 更 加 灵 活 ; pa++ 或 ++pa 合 法, 但 a++ 不 合 法 ; *(pa+i) 与 pa[i] 等 价, 表 示 第 i+1 的 元 素 ; a[i] <=> pa[i] <=> *(pa+i) <=> *(a+i) 17
指 针 数 组 指 针 数 组 : 数 组 的 元 素 都 是 指 针 变 量 指 针 数 组 的 声 明 : 类 型 标 识 符 * 指 针 数 组 名 [n] int a[]={0,2,4,8}; int b[]={1,3,5,7}; int c[]={2,3,5,8}; int *pa[3]={a,b,c}; // 声 明 一 个 有 三 个 元 素 的 指 针 数 组 // pa[0]=a, pa[1]=b, pa[2]=c 例 : 使 用 三 种 方 法 引 用 数 组 元 素 ex06_pointer_05.cpp 18
二 维 数 组 C++ 中, 二 维 数 组 是 按 行 顺 序 存 放 在 内 存 中 的, 可 以 理 解 为 一 维 数 组 组 成 的 一 维 数 组 例 :int A[2][3]={{1,2,3},{7,8,9}}; 可 以 理 解 为 : A A[0] A 00 A 01 A 02 A[1] A 10 A 11 A 12 A[0][0] A[0][1] A[0][2] A[1][0] A[1][1] A[1][2] A[0] A[1] ( 第 一 行 的 首 地 址 ) ( 第 二 行 的 首 地 址 ) A[0], A[1] 称 为 行 数 组 19
二 维 数 组 与 指 针 int A[2][3]={{1,2,3},{7,8,9}}; int * pa = A[0]; // 行 数 组 A[0] 的 首 地 址, 等 价 于 pa=&a[0][0] int * pa1 = A[1]; // 行 数 组 A[1] 的 首 地 址, 即 &A[1][0] *pa = 11; // 等 价 于 A[0][0]=11 *(pa+2) = 12; // 等 价 于 A[0][2]=12 *(pa+4) = 13; // 等 价 于 A[1][1]=13 ex06_pointer_06.cpp 引 用 二 维 数 组 的 元 素 可 以 通 过 数 组 名 和 指 针 运 算 进 行 for (int i=0; i<m; i++) { for (int j=0; j<n; j++) cout << *(*(A+i)+j); cout << "\n"; } ex06_pointer_07.cpp 20
二 维 数 组 与 指 针 对 于 二 维 数 组 A, 虽 然 A A[0] 都 是 数 组 首 地 址, 但 二 者 指 向 的 对 象 不 同 : A[0] 是 一 维 数 组 的 名 字, 它 指 向 的 是 行 数 组 A[0] 的 首 元 素, 对 其 进 行 * 运 算 时, 得 到 的 是 A[0] 的 首 元 素 的 值, 即 *A[0] 与 A[0][0] 是 相 同 的 ; 而 A 是 一 个 二 维 数 组 的 名 字, 它 指 向 的 是 它 的 首 元 素, 而 它 的 元 素 都 是 一 维 数 组 ( 即 行 数 组 ), 因 此, 它 的 指 针 移 动 单 位 是 行, 所 以 A+i 指 向 的 是 第 i 个 行 数 组, 即 指 向 A[i] 对 A 进 行 * 运 算 时, 得 到 的 是 一 维 数 组 A[0] 的 首 地 址, 即 *A 与 A[0] 是 同 一 个 值 当 用 int * p 声 明 指 针 p 时,p 指 向 的 是 一 个 int 型 数 据, 而 不 是 一 个 地 址, 因 此, 用 A[0] 对 p 赋 值 是 正 确 的, 而 用 A 对 p 赋 值 是 错 误 的! int A[2][3]={{1,2,3},{7,8,9}}; int * pa = A; // ERROR! int * pa = A[0]; // OK 设 指 针 pa=&a[0][0], 则 A[i][j] <=> *(pa+n*i+j) 21
行 指 针 行 指 针 / 指 向 一 维 数 组 的 指 针 : 以 一 维 数 组 为 基 本 类 型, 即 将 一 维 数 组 看 作 一 个 整 体 类 型 标 识 符 (* 指 针 名 )[n] 该 指 针 以 长 度 为 n 的 一 维 数 组 为 基 本 单 位 int A[3][4]; int (* pa)[4] = A; // OK! 注 意 : 不 能 写 成 (*pa)[3] 或 *pa[4] for (int i=0; i<m; i++) { for (int j=0; j<n; j++) cout << *(*(pa + i) + j ); cout << "\n"; } ex06_pointer_08.cpp 22
二 维 数 组 与 行 指 针 二 维 数 组 A[m][n] 数 组 名 A 是 行 地 址 常 量, 数 组 名 A 与 &A[0][0] 等 价 ; A+i=&A[i], *(A+i)=A[i]=&A[i][0]; A[i][j] <=> *(A[i]+j) <=> *(*(A+i)+j) <=> (*(A+i))[j] <=> *(&A[0][0]+n*i+j) 二 维 数 组 A[m][n] 与 行 指 针 (*pa)[n]=a pa=a, A+i=pA+i, *(A+i)+j=*(pA+i)+j; A[i][j] <=> pa[i][j] <=> *(*(pa+i)+j) 23
二 级 指 针 ( 略 ) 二 级 指 针 : 指 向 指 针 的 指 针 变 量 类 型 标 识 符 ** 指 针 名 二 级 指 针 存 放 的 是 另 一 个 指 针 的 地 址 int a = 3; int *pa = &a; int **ppa = &pa; // OK! ex06_pointer_09.cpp 注 : 二 级 指 针 不 做 要 求 24
指 针 与 引 用 引 用 与 指 针 int a = 3; int * pa = &a; // 指 针 引 用 是 变 量 的 别 名 ; 引 用 必 须 初 始 化, 且 不 能 修 改 ; 引 用 只 针 对 变 量, 函 数 没 有 引 用 ; 传 递 大 量 数 据 时, 最 好 使 用 指 针 ; 用 引 用 能 实 现 的 功 能, 用 指 针 都 能 实 现 引 用 作 为 函 数 参 数 的 优 点 传 递 方 式 与 指 针 类 似, 但 可 读 性 强 ; 函 数 调 用 比 指 针 更 简 单 安 全 ; int & ra = a; // 引 用 25
指 针 作 为 函 数 参 数 指 针 作 为 函 数 参 数 以 地 址 方 式 传 递 数 据 形 参 是 指 针 时, 实 参 可 以 是 指 针 或 地 址 void split(double x, int * n, double * f) double x, x2; int x1; split(x, &x1, &x2) ex06_pointer_10.cpp 当 函 数 间 需 要 传 递 大 量 数 据 时, 开 销 会 很 大 此 时, 如 果 数 据 是 连 续 存 放 的, 则 可 以 只 传 递 数 据 的 首 地 址, 这 样 就 可 以 减 小 开 销, 提 高 执 行 效 率! 26
指 针 作 为 函 数 参 数 指 针 作 为 函 数 参 数 的 三 个 作 用 使 形 参 和 实 参 指 向 共 同 的 内 存 地 址 ; 减 小 函 数 间 数 据 传 递 的 开 销 ; 传 递 函 数 代 码 的 首 地 址 ( 后 面 介 绍 ) Tips: 如 果 在 被 调 函 数 中 不 需 要 改 变 指 针 所 指 向 的 对 象 的 值, 则 可 以 将 形 参 中 的 指 针 声 明 为 指 向 常 量 的 指 针 27
指 针 型 函 数 当 函 数 的 返 回 值 是 地 址 时, 该 函 数 就 是 指 针 型 函 数 指 针 型 函 数 的 定 义 数 据 类 型 * 函 数 名 ( 形 参 列 表 ) { 函 数 体 } 28
指 向 函 数 的 指 针 在 程 序 运 行 过 程 中, 不 仅 数 据 要 占 用 内 存 空 间, 函 数 也 要 在 内 存 中 占 用 一 定 的 空 间 函 数 名 就 代 表 函 数 在 内 存 空 间 中 的 首 地 址 用 来 存 放 这 个 地 址 的 指 针 就 是 指 向 该 函 数 的 指 针 函 数 指 针 的 定 义 数 据 类 型 (* 函 数 指 针 名 )( 形 参 列 表 ) 这 里 的 数 据 类 型 和 形 参 列 表 应 与 其 指 向 的 函 数 相 同 注 : 函 数 名 除 了 表 示 函 数 的 首 地 址 外, 还 包 括 函 数 的 返 回 值 类 型, 形 参 个 数 类 型 顺 序 等 信 息 Tips: 可 以 象 使 用 函 数 名 一 样 使 用 函 数 指 针 29
函 数 指 针 函 数 指 针 需 要 赋 值 后 才 能 使 用 int Gcd(int x, int y); int Lcm(int x, int y); int (* pf)(int, int); // 声 明 函 数 指 针 pf = Gcd; // pf 指 向 函 数 Gcd cout << " 最 大 公 约 数 :" << pf(a,b) << endl; pf = Lcm; // pf 指 向 函 数 Lcm cout << " 最 小 公 倍 数 :" << pf(a,b) << endl; ex06_pointer_11.cpp 30
持 久 动 态 内 存 分 配 动 态 内 存 申 请 --- new 动 态 内 存 释 放 --- delete 动 态 数 组 的 申 请 与 释 放 在 被 调 函 数 中 申 请 动 态 内 存, 返 回 给 主 调 函 数 31
动 态 内 存 分 配 若 在 程 序 运 行 之 前, 不 能 够 确 切 知 道 数 组 中 元 素 的 个 数, 如 果 声 明 为 很 大 的 数 组, 则 可 能 造 成 浪 费, 如 果 声 明 为 小 数 组, 则 可 能 不 够 用 此 时 需 要 动 态 分 配 空 间, 做 到 按 需 分 配 动 态 内 存 分 配 相 关 函 数 申 请 内 存 空 间 :new 释 放 内 存 空 间 :delete 每 个 程 序 在 执 行 时 都 会 占 用 一 块 可 用 的 内 存, 用 于 存 放 动 态 分 配 的 对 象, 此 内 存 空 间 称 为 自 由 存 储 区 (free store) 或 堆 (heap) 32
申 请 内 存 空 间 申 请 单 个 存 储 单 元 px = new 数 据 类 型 ; px = new 数 据 类 型 ( 初 始 值 ); 申 请 用 于 存 放 指 定 数 据 类 型 数 据 的 内 存 空 间, 若 申 请 成 功, 则 返 回 该 内 存 空 间 的 地 址, 并 赋 值 给 指 针 px; 若 申 请 不 成 功, 则 返 回 0 或 NULL 释 放 由 new 申 请 的 存 储 单 元 delete px; // 释 放 由 new 申 请 的 内 存 空 间 注 :px 必 须 是 由 new 操 作 的 返 回 值! 33
动 态 内 存 数 组 创 建 一 维 动 态 数 组 px = new 数 据 类 型 [ 数 组 长 度 ]; ex06_pointer_new01.cpp px = new 数 据 类 型 [ 数 组 长 度 ](); // 赋 初 值 0 这 里 初 始 化 时 只 能 将 全 部 元 素 设 置 为 0, 而 不 能 象 数 组 变 量 那 样 用 初 始 化 列 表 赋 初 值 (C++11 新 标 准 已 加 入 该 功 能 ) 34
动 态 内 存 数 组 创 建 多 维 动 态 数 组 px = new 数 据 类 型 [n 1 ][n 2 ]...[n m ]; 注 : 此 时 px 不 是 普 通 的 指 针, 而 是 : (* px)[n 2 ]...[n m ] 动 态 数 组 的 释 放 delete[] px; // 释 放 由 new 建 立 的 数 组 35
动 态 内 存 举 例 例 : 给 定 一 个 正 整 数 N, 求 出 N 个 最 小 的 素 数 int main() { int N; cout << "Input N: "; cin >> N; int * pa = new int[n]; // 申 请 内 存 空 间 int i, flag, k=0, n=2; ex06_pointer_new02.cpp while (k < N) // 寻 找 N 个 素 数 { flag = 0; for(i=2; i<n; i++) if (n % i == 0) {flag = 1; break;} if (flag==0) { pa[k] = n; k++; } } n++; for(i=0; i<k && pa[i]<=sqrt(n); i++) if (n % pa[i] == 0) {flag = 1; break;} 36
动 态 内 存 举 例 例 : 将 前 面 的 例 子 写 成 函 数 形 式 int * find_prime(int N) { int * pa = new int[n]; // 申 请 内 存 空 间 } int i, flag, k=0, n=2; while (k < N) // 寻 找 N 个 素 数 { flag = 0; for(i=2; i<n; i++) if (n % i == 0) {flag = 1; break;} if (flag==0) { pa[k] = n; k++; } n++; } return pa; 注 : 在 主 调 函 数 中, 如 果 不 再 需 要 pa, 则 需 用 delete[] 释 放 37
字 符 串 ( 字 符 数 组 ) 字 符 串 的 表 示 字 符 串 输 入 输 出 字 符 串 操 作 --- 相 关 函 数 字 符 操 作 函 数 38
字 符 串 字 符 串 的 表 示 : 字 符 数 组 char str[5]={'m','a','t','h','\0'}; char str[5]="math"; // OK char str[]="math"; // OK, 只 能 用 于 初 始 化 字 符 串 以 "\0" 为 结 束 标 志 使 用 双 引 号 时, 会 自 动 在 最 后 添 加 结 束 标 志 例 : char str[20]="c++ and Matlab"; for(int i=0;i<20;i++) if (str[i]!='\0') cout << str[i] << endl; else break; ex06_str_print.cpp char str[5]; str = "Math"; // ERROR: 一 维 数 组, 不 能 直 接 赋 值! 39
字 符 串 输 入 输 出 字 符 串 的 输 出 例 : char str[5]="math"; cout << str; 输 出 字 符 中 不 含 "\0" 可 使 用 下 标 输 出 单 个 字 符 字 符 串 的 输 入 例 : char str[5]; cin >> str; 输 入 单 个 字 符 串 时, 中 间 不 能 有 空 格 一 次 输 入 多 个 字 符 串 时, 以 空 格 隔 开 ex06_str_01.cpp 40
字 符 串 输 入 输 出 例 : char str1[5], str2[5], str3[5]; cin >> str1 >> str2 >> str3; 运 行 时 输 入 数 据 :How are you? 内 存 中 变 量 状 态 如 下 : str1: H o w \0 str2: a r e \0 str3: y o u? \0 例 : char str[13]; cin >> str; 运 行 时 输 入 数 据 :How are you? 内 存 中 变 量 状 态 如 下 : ex06_str_02.cpp str1: H o w \0 41
字 符 串 输 入 cin.getline(str,n, 结 束 符 ); 连 续 读 入 多 个 字 符 ( 可 以 有 空 格 ), 直 到 读 满 N-1 个, 或 遇 到 指 定 的 结 束 符 不 存 储 结 束 符 结 束 符 可 以 省 略, 默 认 为 '\n' ( 换 行 ) 例 : char str[13]; cin.getline(str,13); 单 个 字 符 的 输 入 ex06_str_03.cpp getchar(); char ch; ch=getchar(); 42
字 符 串 操 作 字 符 串 相 关 函 数 ( 需 包 含 头 文 件 cstring 和 cstdlib ) 函 数 描 述 用 法 strlen 求 字 符 串 长 度 strlen(str) strcat 字 符 串 连 接 strcat(dest,src) strcpy 字 符 串 复 制 strcpy(dest,src) strcmp 字 符 串 比 较 strcmp(str1,str2) atoi 将 字 符 串 转 换 为 整 数 atoi(str) atol 将 字 符 串 转 换 为 long atol(str) atof 将 字 符 串 转 换 为 double atof(str) itoa 将 整 数 转 换 为 字 符 串 itoa(int,str,raidx) ( 更 多 函 数 见 http://www.cppreference.com) 43
字 符 串 操 作 strlen(str) 返 回 字 符 串 str1 的 长 度 ( 不 含 结 束 符 ) strcat(str1,str2) 将 str2 的 全 部 内 容 添 加 到 str1 中,str2 的 内 容 保 留 strncat(str1,str2,n) 将 str2 的 内 容 添 加 到 str1 中, 至 多 添 加 n 个 字 符 strcmp(str1,str2) 按 字 典 顺 序 比 较 str1 和 str2 的 大 小 如 果 str1>str2, 则 返 回 一 个 正 数 ; str1<str2, 则 返 回 一 个 负 数 ; 相 等 则 返 回 0 44
字 符 串 操 作 strncmp(str1,str2,n) 按 字 典 顺 序 比 较 str1 和 str2 的 前 n 个 字 符 的 大 小 strcpy(str1,str2) 将 str2 的 全 部 内 容 复 制 到 str1 中 ; str1 的 长 度 应 该 不 小 于 str2 的 长 度 strncpy(str1,str2,n) 将 str2 的 前 n 个 字 符 复 制 到 str1 中 ; 若 n 大 于 str2 的 长 度, 则 复 制 全 部 内 容 例 : ex06_str_04.cpp int N = 20; char str1[n]; char str2[]="hello world!"; strncpy(str1,str2,n-1); // 实 际 复 制 字 符 个 数 不 超 过 str2 长 度 45
字 符 串 操 作 x=atoi(str) x=atol(str) x=atof(str) 分 别 将 str 转 化 为 整 型 长 整 型 和 双 精 度 型 数 据 str 必 须 是 由 数 字 组 成 的 字 符 串, 否 则 结 果 为 0 例 :int x; double y; x=atoi("66"); // x=66 y=atof("14.5"); // y=14.5 ex06_str_05.cpp itoa(int,str,radix) 按 指 定 的 进 制 将 一 个 整 数 转 化 为 字 符 串 例 : char str[5]; itoa(66,str,16); // 按 16 进 制 转 换 46
字 符 检 测 C++ 字 符 检 测 函 数 ( 头 文 件 cctype) 函 数 描 述 用 法 isdigit 是 否 为 数 字 isalpha 是 否 为 字 母 isalnum 是 否 为 字 母 或 数 字 islower 是 否 为 小 写 isupper 是 否 为 大 写 isspace 是 否 为 空 格 isprint 是 否 为 可 打 印 字 符, 包 含 空 格 isgraph 是 否 为 可 打 印 字 符, 不 含 空 格 isdigit('3') isalpha('a') isalnum('c') islower('b') isupper('b') isspace(' ') isprint('a') isgraph('a') ispunct 除 字 母 数 字 空 格 外 的 可 打 印 字 符 ispunct('*') iscntrl 是 否 为 控 制 符 iscntrl('\n') 47
字 符 检 测 C++ 字 符 转 换 函 数 ( 头 文 件 cctype) 函 数 描 述 用 法 tolower 将 大 写 转 换 为 小 写 toupper 将 小 写 转 换 为 大 写 tolower('a') toupper('a') 以 上 检 测 和 转 换 函 数 只 针 对 单 个 字 符, 而 不 是 字 符 串! 48
字 符 与 整 数 字 符 与 整 型 数 据 之 间 的 转 换 例 : char x='2'; int y=x; int z=x-'0'; cout << "x=" << x << endl; // x='2' 是 字 符 cout << "y=" << y << endl; // y=50 是 整 数 cout << "z=" << z << endl; // z=50-48=2 是 整 数 字 符 数 据 与 整 型 数 据 之 间 的 转 换 是 通 过 ASCII 码 实 现 的 字 符 参 加 算 术 运 算 时, 自 动 转 换 为 整 数 atoi 等 只 能 作 用 在 字 符 串 上! 不 能 作 用 在 字 符 上! 49
课 后 练 习 课 后 练 习 ( 自 己 练 习 ) (1) 教 材 第 七 章 : 字 符 与 字 符 串 p253 7.19 (2) 教 材 第 十 一 章 : 指 针 p358 11.2, 11.3, 11.5, 11.6, 11.7 p360 11.9, 11.10 p363 11.11, 11.12, 11.13, 11.15, 11.16 50
课 后 练 习 课 后 练 习 ( 自 己 练 习 ) (3) 已 知 一 个 数 组, 数 组 名 为 x, 试 用 一 条 语 句 算 出 该 数 组 的 元 素 个 数 ( 提 示 : 使 用 sizeof 函 数 ) (4) 阅 读 下 面 的 代 码 int a[]={6,21,12,34,55}; int * pa = a, * pb; *pa = 5; *(pa+2) = 8; *(pa++) = *a + 42; pb = pa; *(++pb) = 45; 指 出 最 后 a 的 值,*pa 的 值,*pb 的 值 51
上 机 作 业 1) 有 17 人 围 成 一 圈, 编 号 1~17, 从 1 号 开 始 报 数, 报 到 3 的 倍 数 的 人 离 开, 一 直 数 下 去, 直 到 最 后 只 剩 一 人, 求 此 人 编 号 程 序 取 名 hw06_01.cpp 2) 编 写 函 数, 交 换 两 个 双 精 度 变 量 的 值, 分 别 用 引 用 和 指 针 实 现 函 数 分 别 为 swap_ref 和 swap_point, 并 在 主 函 数 中 定 义 两 个 双 精 度 变 量, 从 键 盘 接 受 输 入, 并 将 交 换 后 的 值 在 屏 幕 上 输 出 ( 程 序 名 hw06_02.cpp) void swap_ref(double & ra, double & rb); void swap_point(double * pa, double * pb); 3) 求 最 小 的 前 100 个 素 数, 存 放 在 数 组 p 中, 并 分 别 使 用 下 列 方 式 在 屏 幕 上 输 出 p, 每 行 输 出 10 个, 程 序 取 名 为 hw06_03.cpp 方 式 一 : 数 组 名 + 下 标 运 算 ; 方 式 二 : 数 组 名 + 指 针 运 算 ; 方 式 三 : 指 针 + 指 针 运 算 52
上 机 作 业 4) 编 写 函 数, 计 算 两 个 矩 阵 的 乘 积 Z=X*Y 其 中 X R m p,y R p n, Z R m n, 要 求 函 数 对 任 意 的 正 整 数 m,p,n 都 能 实 现 矩 阵 相 乘 void matrix_prod(double * px, double * py, double * pz, int m, int p, int n); 提 示 : 这 里 px, py, pz 分 别 指 向 X[0][0], Y[0][0] 和 Z[0][0] 程 序 取 名 为 hw06_04.cpp 5) 生 成 一 个 6 阶 矩 阵 T( 定 义 见 右 方 ), 并 分 别 使 用 下 列 方 式 按 矩 阵 形 式 输 出 : 方 式 一 : 数 组 名 + 下 标 运 算 ; 方 式 二 : 数 组 名 + 指 针 运 算 ; 方 式 三 : 行 指 针 + 指 针 运 算 ; ( 定 义 矩 阵 时, 要 使 用 循 环 实 现, 程 序 名 hw06_05.cpp) T 1 2 3 4 5 6 2 1 2 3 4 5 3 2 1 2 3 4 = 4 3 2 1 2 3 5 4 3 2 1 2 6 5 4 3 2 1 53
上 机 作 业 6) 给 定 两 个 一 维 数 组 a 和 b, 其 中 a 中 的 数 据 是 无 序 的, 而 b 中 的 数 据 按 升 序 排 列 试 统 计 a 的 所 有 元 素 中, 大 于 b 的 第 k 个 元 素 且 小 于 第 k+1 个 元 素 的 数 据 个 数 其 中 a=[98,12,34,71,43,54,28,33,65,56], b=[10,30,50,80,100] 要 求 将 结 果 存 放 在 数 组 c 中, 其 中 c[k] 表 示 数 组 a 中 大 于 b[k] 而 小 于 b[k+1] 的 元 素 个 数 程 序 名 hw06_06.cpp 7) 二 进 制 转 十 进 制 程 序 取 名 为 hw06_07.cpp 编 写 函 数, 将 一 个 用 字 符 串 表 示 的 二 进 制 数 转 化 为 十 进 制 数, 如 10001 所 对 应 的 十 进 制 数 为 17, 在 主 函 数 中 用 1100110011001100 来 测 试 int bin2dec(const char * const str); 提 示 : 如 何 将 一 个 字 符 转 化 成 数 字 ( 借 助 字 符 串 函 数 或 字 符 加 减 运 算 ) 54
上 机 作 业 8) 字 符 易 位 破 译 程 序 取 名 为 hw06_08.cpp 编 写 函 数, 测 试 两 个 字 符 串 是 否 字 符 异 位 相 等, 即 两 个 字 符 串 中 包 含 的 字 母 是 相 同 的, 但 次 序 可 以 不 同, 如 silent 和 listen 是 字 符 异 位 相 等, 但 baac 与 abcc 不 是 bool isanagram(const char * const str1, const char * const str2); 提 示 : 先 对 字 符 串 进 行 排 序, 然 后 再 比 较 55