跳过正文

丙加·第4章·答案

·567 字·3 分钟·
目录

1. 使用 printfstd::cout 输出指定内容
#

#include <cstdio>
#include <iostream>
int main() {
    const char stuff1[] = "eggplant";
    const char stuff2[] = "tomato";

    const char donation1[] = "my NUTRIENTS";
    const char donation2[] = "ANTIOXIDANTS";

    // 使用printf输出第一行
    printf("If I'm an %s Then I will give you %s\n", stuff1, donation1);

    // 使用std::cout输出第二行
    std::cout << "If I'm a " << stuff2 << " Then I will give you " << donation2 << std::endl;

    return 0;
}

2. 使用 C 和 C++实现数字输入和加法运算
#

C 版本:

#include <cstdio>
int main() {
    int a, b;
    printf("请输入两个数字,用空格分隔:");
    scanf("%d %d", &a, &b);
    printf("%d + %d = %d\n", a, b, a + b);
    return 0;
}

C++版本:

#include <iostream>
int main() {
    int a, b;
    std::cout << "请输入两个数字,用空格分隔:";
    std::cin >> a >> b;
    std::cout << a << " + " << b << " = " << a + b << std::endl;
    return 0;
}

3. 使用 C++版本处理中文数字输入
#

当输入 “十五 十二” 时,程序会出现问题,因为 std::cin 无法直接将中文数字转换为整数。程序会尝试读取但失败,变量 ab 将保持未初始化状态或默认值,输出结果可能是类似 0 + 0 = 0114514 + 1919810 = 2063324 这样的无意义(?)结果。

4.添加了调试代码
#

#include <cstdio>
int main() {
    int a, b;
    printf("请输入两个数字,用空格分隔:");
    int count = scanf("%d %d", &a, &b);

    printf("%d + %d = %d\n", a, b, a + b);

    printf("成功读入了%d个参数\n", count);
    char remain[100] = "";

    if(count < 2) {
        fgets(remain, 100, stdin);
        printf("缓冲区还剩下:%s", remain);
    }

    return 0;
}

测试结果分析:

  1. 正常输入阿拉伯数字(如 “15 12”)

    • 输出:15 + 12 = 27
    • count 值为 2,表示成功读取了两个参数
    • 不会进入 if 语句块,不会显示缓冲区剩余内容
  2. 输入 “15 十二”

    • 输出:15 + 114514 = 114529(第二个数字可能是随机值)
    • count 值为 1,表示只成功读取了一个参数
    • 会进入 if 语句块,显示缓冲区还剩下:" 十二"
  3. 输入 “十五 十二”

    • 输出:114514 + 1919810 = 2063324(两个数字都是随机值)

    • count 值为 0,表示没有成功读取任何参数

    • 会进入 if 语句块,显示缓冲区还剩下:“十五 十二”

启示与解决思路
#

说白了,这堆问题核心就一件事:C 和 C++里那些输入函数(scanfstd::cin)都挺娇气的,你喂它吃错东西——比如该吃数字你喂它中文——它就撂挑子了。 scanf 的返回值代表它成功得到了几个 % 参数,比如 int count = scanf("%d %d", &a, &b); 里面预期就该返回 2。剩下的数据会留在输入缓冲区里面,剩给下一次输入;而这往往会破坏下一次输入,就像 DNA 插入了一个碱基对那样:

#include <stdio.h>

int main() {
    int id = 0;
    char name[100] = "";

    printf("输入你的学号\n");
    scanf("%d", &id);

    printf("输入你的姓名\n");
    scanf("%s", name);

    printf("你好,%s,你的学号是%d", name, id);
    return 0;
}

交互:

输入你的学号
213ab
输入你的姓名
你好,ab,你的学号是213

这就是因为多余的 ab 剩在了输入缓冲区,导致下一个输入直接拿走了 'ab\n' (当然,\n 丢弃了),用户无法输入。

std::cin 就更闷葫芦一点,它只会设置一个标志位 std::cin.fail(),然后开始傲娇,拒绝继续读入(涉及基于 iostream 的所有输入方式,包括 std::cin 本身、还有 getline 等等)。
对于 scanf,判断输入是否有误的方式就是检查返回值是不是 % 参数的个数。另外,如果输入有误,因为有 黏糊糊的“脏数据”留在输入缓冲区里了,所以得自己想办法 事后 清理干净。
对于 std::cin,就需要检查 std::cin.fail() 是不是 true,如果它果然开始傲娇了,你就该 带 TA 去咖啡馆摸摸头 告诉 TA 没事了(cin.clear()),然后把剩下的清理掉,这个 std::cin 自己有方法,就是 cin.ignore()。然后就一切如常了。

至于为什么输入 十二 十五 会引发错误,就更简单了,对于 scanfstd::cin,它们只接受阿拉伯数字,十二 十五 对它们来说只是普通的字符串,当然不能被 %d 识别了。如果你硬要处理汉字,那压力就到你身上了——你得自己写解析。所以这种情况最好的方式就是直接报错,告诉用户该怎么输入。毕竟可能的错误输入是无穷的,而合理的就那么一两个。

目前,由于还没有学习控制语句和更多 IO 技术,可以先了解这些基本思路,后续学习你会知道具体如何实现的。

5. 日记本
#

#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::ifstream inputFile("diary.txt");
    
    // 检查文件是否成功打开
    if (!inputFile.is_open()) {
        std::cerr << "Unable to open diary.txt." << std::endl;
        std::cerr << "Please make sure it exists." << std::endl;
        return 1;
    }
    
    std::ofstream outputFile("decrypted_diary.txt");
    
    // 检查输出文件是否成功创建
    if (!outputFile.is_open()) {
        std::cerr << "Unable to create decrypted_diary.txt" << std::endl;
        inputFile.close();
        return 1;
    }
    
    char ch;
    std::string decryptedContent;
    
    // 读取每个字符并解密
    while (inputFile.get(ch)) {
        // 将ASCII码减1
        char decryptedChar = ch - 1;
        outputFile << decryptedChar;
        decryptedContent += decryptedChar;
    }
    
    // 关闭文件
    inputFile.close();
    outputFile.close();
    
    // 在控制台显示解密结果
    std::cout << "decrypted!" << std::endl;
    std::cout << "origin: cbojttzvnnfooup.ezjtv.xp.svep" << std::endl;
    std::cout << "decrypted: " << decryptedContent << std::endl;
    std::cout << "saved to decrypted_diary.txt" << std::endl;
    
    return 0;
}

或者C版本,逻辑稍有不同:

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *inputFile = fopen("diary.txt", "r");
    FILE *outputFile = fopen("decrypted_diary.txt", "w");
    
    if (inputFile == NULL) {
        printf("Unable to open diary.txt.\n");
        printf("Please make sure it exists.\n");
        return 1;
    }
    
    if (outputFile == NULL) {
        printf("Unable to create decrypted_diary.txt\n");
        fclose(inputFile);
        return 1;
    }
    
    int ch;
    printf("decrypted!\n");
    printf("origin: cbojttzvnnfooup.ezjtv.xp.svep\n");
    printf("decrypted: ");
    
    // 读取每个字符并解密
    while ((ch = fgetc(inputFile)) != EOF) {
        char decryptedChar = ch - 1;
        fputc(decryptedChar, outputFile);
        putchar(decryptedChar);
    }
    
    printf("\nsaved to decrypted_diary.txt\n");
    
    fclose(inputFile);
    fclose(outputFile);
    
    return 0;
}
命令提示符@CommandPrompt-Wang
作者
命令提示符@CommandPrompt-Wang