【C++】深入理解C语言中的特殊字符处理与问题分析优化



博客主页:[小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C++


文章目录



💯前言

  • 在C语言编程过程中,格式化输出函数printf是一个高频使用的工具。然而,由于其支持格式化字符串,某些特殊字符(如%)的输出和处理经常导致困惑。本文通过具体问题的剖析,包括在洛谷平台的编程题目和相关代码的优化实践,系统地讲解了printf中特殊字符处理的机制、常见错误的排查方法,以及代码优化的技巧。希望通过这一篇文章,读者能对C语言的printf机制和编程逻辑有更深刻的理解。
    C++ 参考手册

💯题目:B2090 年龄与疾病

B2090 年龄与疾病

题目描述:

某医院进行了一项研究,想知道某项疾病是否与年龄有关。因此对以往的诊断记录进行整理,统计0-18、19-35、36-60、61及以上这四个年龄段的患者人数占总患者人数的比例。

输入格式

输入共2行:

  1. 第一行包含一个整数 N N N ( 0 < N ≤ 100 ) (0 < N \leq 100) (0<N≤100),表示总患者人数。
  2. 第二行包含 N N N 个整数,代表这 N N N 个患者就诊时的年龄。

输出格式

输出共4行:

  1. 第1行包含一个百分数,表示0-18岁这个年龄段的患者人数占总患者人数的比例,精确到小数点后2位。
  2. 第2行包含一个百分数,表示19-35岁这个年龄段的患者人数占总患者人数的比例,精确到小数点后2位。
  3. 第3行包含一个百分数,表示36-60岁这个年龄段的患者人数占总患者人数的比例,精确到小数点后2位。
  4. 第4行包含一个百分数,表示61岁及以上这个年龄段的患者人数占总患者人数的比例,精确到小数点后2位。

输入输出样例

输入样例 #1

复制代码
10
1 11 21 31 41 51 61 71 81 91

输出样例 #1

复制代码
20.00%
20.00%
20.00%
40.00%

输入样例 #2

复制代码
12
10 19 96 94 58 57 34 18 99 5 13

输出样例 #2

复制代码
25.00%
25.00%
16.67%
33.33%

💯初始代码分析与问题排查

初始代码如下:

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
    int n = 0;
    cin >> n;
    int arr[n];
    int sum = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
    for(int i = 0; i < n; i++)
    {
        cin >> arr[i];
        sum++;
        if(i <= 18)
            sum1++;
        else if(i <= 35)
            sum2++;
        else if(i <= 60)
            sum3++;
        else
            sum4++;
    }

    double rate1 = 100.0 * sum1 / sum;
    double rate2 = 100.0 * sum2 / sum;
    double rate3 = 100.0 * sum3 / sum;
    double rate4 = 100.0 * sum4 / sum;
    printf("%0.2lf% ", rate1);

    return 0;    
}

问题点分析

  1. 逻辑错误:

    • 判断条件 if(i <= 18) 中,i 是数组的索引,而不是输入的年龄值。这导致判断逻辑与题目要求不符。
    • 索引 i 的范围是 0n-1,无法正确反映年龄范围。
  2. 范围错误:

    • 题目要求的范围是 0-18, 19-35, 36-60, 61及以上,但代码未正确实现。
    • 代码中未对数组的值进行比较,而是直接比较索引值。
  3. 数组定义错误:

    • 在C++中,int arr[n]; 使用了变长数组,这是C99标准支持的特性,但并非所有C++编译器都支持。应使用动态内存分配(如new)或标准容器(如vector)。
  4. 输出格式错误:

    • printf("%0.2lf% ", rate1); 多余的空格和单独的%符号导致输出不符合题目要求。
    • 百分号%需要用%%来表示,确保格式化输出。
  5. 未释放动态分配内存:

    • 如果使用动态数组,代码未正确释放分配的内存。

💯修正后的代码与优化

cpp 复制代码
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
    int n;
    cin >> n;
    int* arr = new int[n]; // 动态分配数组
    int sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;

    for (int i = 0; i < n; i++) {
        cin >> arr[i];
        if (arr[i] >= 0 && arr[i] <= 18)
            sum1++;
        else if (arr[i] >= 19 && arr[i] <= 35)
            sum2++;
        else if (arr[i] >= 36 && arr[i] <= 60)
            sum3++;
        else if (arr[i] >= 61)
            sum4++;
    }

    // 计算比例
    printf("%.2lf%%\n", 100.0 * sum1 / n);
    printf("%.2lf%%\n", 100.0 * sum2 / n);
    printf("%.2lf%%\n", 100.0 * sum3 / n);
    printf("%.2lf%%\n", 100.0 * sum4 / n);

    delete[] arr; // 释放动态分配内存
    return 0;
}

修正与优化要点

  1. 修正逻辑错误:

    • 使用 arr[i] 比较输入的年龄值,而不是索引 i
  2. 调整范围判断:

    • 按题目要求分别比较 0-18, 19-35, 36-60, 61及以上
  3. 动态内存分配:

    • 使用 new 动态分配数组,并在程序结束时使用 delete[] 释放内存,防止内存泄漏。
  4. 输出格式修正:

    • 使用 %% 正确输出百分号。
    • 每行输出结果以换行符 \n 结尾,确保格式正确。
  5. 代码简洁性:

    • 合理命名变量,增强代码可读性。
    • 省去冗余的 sum++ 操作,直接用输入数量 n 作为总人数。

💯拓展:printf 中的特殊字符处理

在C语言的printf函数中,有一些特殊字符需要注意处理,类似于上述代码中使用的%%。以下是常见的特殊字符及其用法:

1. 百分号 %

  • 原因% 是格式说明符的起始符号,用于标记格式化占位符(如 %d, %f)。如果需要输出实际的 % 符号,必须使用 %%

  • 示例

    c 复制代码
    printf("成功率为 50%%\n");

    输出:

    复制代码
    成功率为 50%

2. 反斜杠 \

  • 原因 :反斜杠 \ 是转义字符的起始符号,必须用双反斜杠 \\ 表示实际的 \

  • 示例

    c 复制代码
    printf("This is a backslash: \\\n");

    输出:

    复制代码
    This is a backslash: \

3. 双引号 "

  • 原因 :双引号 " 在字符串常量中需要用转义字符 \" 表示。

  • 示例

    c 复制代码
    printf("She said, \"Hello, World!\"\n");

    输出:

    复制代码
    She said, "Hello, World!"

4. 常见转义字符

  • 换行符\n
  • 制表符\t
  • 回车\r
  • 退格\b
  • 响铃\a
  • 反斜杠\\
  • 双引号\"

💯总结

通过对题目"年龄与疾病"的深入分析和代码优化,我们不仅修正了代码中的逻辑问题和格式错误,还系统性地探讨了C语言中printf函数处理特殊字符的机制。这些知识点不仅适用于此题目,还对其他编程场景具有指导意义。

在实际开发中,理解格式化输出函数的工作机制,掌握正确的特殊字符处理方法,是写出健壮代码的重要一步。希望本文能帮助读者从细节中理解C语言编程的核心思想,从而在复杂问题的解决中游刃有余。



相关推荐
努力努力再努力wz7 小时前
【Linux实践系列】:用c/c++制作一个简易的进程池
linux·运维·数据库·c++·c
易保山1 天前
MIT6.S081 - Lab7 Locks(锁优化 | 并发安全)
linux·操作系统·c
Mr_Chenph2 天前
Visual Studio Code 开发 树莓派 pico
vscode·c·micropython·pico
dami_king5 天前
用C++手搓一个贪吃蛇?
c++·游戏·c
ShiinaKaze6 天前
VSCode、clangd、mingw 配置与使用
vscode·c·mingw·clangd
易保山6 天前
MIT6.S081 - Lab7 Multithreading(进程调度)
linux·操作系统·c
charlie11451419111 天前
从0开始的构建的天气预报小时钟(基于STM32F407ZGT6,ESP8266 + SSD1309)——第2章——构建简单的ESP8266驱动
stm32·单片机·物联网·学习·c·esp8266
易保山14 天前
MIT6.S081 - Lab6 Copy-on-Write(写时复制)
linux·操作系统·c
Ronin-Lotus15 天前
嵌入式硬件篇---USB&UART串口
嵌入式硬件·c·uart·usb
易保山16 天前
MIT6.S081 - Lab5 Lazy(延迟分配)
linux·操作系统·c