Deaf Grandma:C 语言三版代码分析

分析日期:2026-10-15。分析对象:用户提供的三个版本。题目链接。

1. 题目契约与核心模型

**核验限制:**本轮未读取官方题面。以下业务规则根据你的第三版代码整理,尤其需要核对单次 "BYE" 是否结束,以及数字、标点、空字符串的处理;不能声称参考实现已通过 Codewars。

假定规则:包含 ASCII 小写字母时回复 "HUH?! SPEAK UP, SONNY!";恰好为 "BYE" 时回复 "OK, BYE!" 并结束;其余情况回复 "NO, NOT SINCE 1938!"。返回值是实际写入的回复数量。

前提:length > 0 时,输入指针指向有效且以 '\0' 结尾的字符串,输出数组至少容纳 length 个指针。写入的是字符串字面量,不得释放或修改其内容。

复制代码
current sentence -> exactly "BYE"? -> write farewell -> return count
                 -> otherwise -> contains lowercase? -> HUH / NO -> next
all sentences processed -> return length

2. 三个版本的问题

版本与位置 问题、反例与影响 修复
初版:缺少 <string.h> strlen 没有可见声明,不符合现代 C 对函数声明的要求。 包含 <string.h>。
初版:strlen(*(your_sentences)) 每次取第一句长度。{"HELLO","HI"} 会在第二句扫描时越界;{"HI","HIbye"} 会漏查后半句。前者涉及未定义行为,后者导致误判。 测量当前句,或扫描到 '\0'。
初版:your_sentences[p] == "BYE" 比较地址,不能保证相同内容得到真。由字符数组保存的 "BYE" 就能暴露问题;字符串字面量是否合并也不应作为依据。 使用 strcmp(...) == 0。
初版、中间版:只接受大写和空格 "HELLO!" 被误判;"没有小写字母"与"只含大写和空格"不是同一条件。 按假定题意检测 a~z。
初版、中间版:告别分支与 return 1 告别文本不符合上述契约,也没有立即结束。输入 {"HELLO","HELLO"} 写入两项却返回 1。 告别时写入完整回复并返回 p + 1;遍历结束返回 length。
中间版:strcmp(...) == 1 相等返回 0 ;输入 "BYE" 就不会进入告别分支。不相等时只保证结果正负,不保证恰好为 1。 判断 == 0。
最新版:函数末尾没有返回值 {"HELLO"} 不会进入提前返回分支;若调用者使用最终返回值,行为未定义。 循环后补上 return length;。
三版共有:使用 int 保存下标或长度 strlen 返回 size_t;超出 int 范围时转换不具可移植性。初版有符号下标持续递增还可能溢出;强转 length 不能解决问题。 下标使用 size_t,或使用字符指针遍历。
最新版:q、else continue、完整计数 q 对结果没有作用,else continue 冗余;发现小写后仍继续扫描也没有必要。这些主要影响可读性和常数开销。 删除冗余状态,发现小写立即停止扫描。

3. 参考实现

以下实现基于第 1 节的待核验规则。数组形参使用 [],保持相同的指针接口类型;它们不会自动检查实际数组容量。

复制代码
#include <stddef.h>
#include <string.h>

size_t deaf_grandma_conversation(
    size_t length, const char *const your_sentences[],
    const char *grandma_sentences[])
{
    for (size_t p = 0; p < length; ++p) {
        const char *sentence = your_sentences[p];
        if (strcmp(sentence, "BYE") == 0) {
            grandma_sentences[p] = "OK, BYE!";
            return p + 1;
        }
        int has_lowercase = 0;
        for (const char *ch = sentence; *ch != '\0'; ++ch) {
            if (*ch >= 'a' && *ch <= 'z') {
                has_lowercase = 1;
                break;
            }
        }
        grandma_sentences[p] = has_lowercase
            ? "HUH?! SPEAK UP, SONNY!" : "NO, NOT SINCE 1938!";
    }
    return length;
}

**正确性:**每轮恰好写入一个回复;精确匹配 "BYE" 后返回 p + 1,等于已写入项数。其余句子根据是否存在小写字母选择回复;全部处理后返回 length。提前结束后的输出项不写入。此实现对 length == 0 返回 0,不访问输入或输出数组。

**复杂度:**设实际处理了 k 句,总字符数为 S,时间为 O(k + S) ,额外空间为 O(1) 。不计调用者提供的输出数组;空字符串也需要一次句子处理,因此保留 k 更严谨。

4. 测试矩阵与验证状态

记 H 为听不清回复、N 为年份回复、B 为告别回复。以下是应验证的预期,尚未实际编译或运行。

输入 预期输出及返回值 验证重点
{"hello"};{"HELLO"} 分别为 [H] / 1、[N] / 1 小写判定、无告别返回
{"HELLO!"};{"123"};{""} 均为 [N] / 1,按假定规则 标点、数字、空串
{"BYE"};{"bye"} 分别为 [B] / 1、[H] / 1 精确匹配与大小写
{"HI","BYE","hello"} [N,B] / 2,第三项保持原值 提前结束与写入范围
{"HELLO","HI"};{"HI","HIbye"};length = 0 分别为 [N,N] / 2、[N,H] / 2、返回 0 首句长度错误、空输入

5. 语言依据

代码来自用户粘贴;业务契约仍需与题面核对。C 语言依据可查阅 WG14 N1570(C11 委员会草案):strcmp 为 §7.24.4.2,strlen 为 §7.24.6.3,函数末尾缺少返回值为 §6.9.1 ¶12,整数转换为 §6.3.1.3,字符串字面量为 §6.4.5。上述资料未在本轮重新打开核验。

相关推荐
信奥卷王2 小时前
[GESP202503 六级] 环线(含视频)
算法
CQU_JIAKE2 小时前
10.15【A】
算法
晴天的雨.9922 小时前
【C++】模板进阶
开发语言·c++·算法
木井巳3 小时前
【动态规划】三步问题
java·算法·leetcode·动态规划·推荐算法
楚识科技3 小时前
手写 OCR 识别技术深度解析:从算法原理到政企级落地实现
算法·ocr
leobertlan11 小时前
痛苦系列 | DSP-03 跨越单位圆:Z变换与零极点分析
算法·程序员
蛋蛋的就会顺顺的12 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
开发小能手12312 小时前
答案daanC语言
数据结构·算法
Navigator_Z14 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode