cszhang_123 2025-08-10 15:01 采纳率: 50%
浏览 6
已结题

自己做的输入函数出了问题

一个玄学的问题。

#include<bits/stdc++.h>
#include <windows.h>
#include<conio.h>
using namespace std;
int to_int(string s){int d;for(int i=0;i<s.size();i++){d=d*10;d+=s[i]-'0';}return d;}
int charto_int(char s[]){int d;for(int i=0;i<strlen(s);i++){d=d*10;d+=s[i]-'0';}return d;}
string to_string(int i){if(i==0)return "0";string s;while (i){s=char(i%10+48)+s;i/=10;}return s;}
string getS(){
    char c=' ';string s="";
    while(1){
        c=getch();
        if(c!=' ')s=s+c;
        else break;
    }
    return s;
}
int getI(){
    string s=getS();
    cout <<s<<endl;//22行 
    int i=to_int(s);
    return i;
}
int main(){
    string s1=getS();int a=getI();
    cout << s1 << ' ' << a;
    return 0;
}

运行后按a,b,c,空格,1,2,空格
运行结果是

12
abc 12

但假如把22行注释掉,同样按a,b,c,空格,1,2,空格
结果就成了

abc -2147483636

有人能解释一下吗

  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-08-10 15:08
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    你提到的这个问题是非常典型的输入函数设计问题,涉及到 C++ 的 getch() 函数、字符串处理和整数转换逻辑。我们来逐步分析这个问题。


    一、问题描述

    你编写了一个自定义的 getS() 函数,用于读取用户输入直到遇到空格。然后通过 to_int()charto_int() 将字符串转为整数。在 getI() 中调用了 getS(),并将其打印出来(第22行)。

    运行时:

    • 按下:a b c 空格 1 2 空格
    • 输出结果为:abc 12
    • 但如果注释掉第22行的 cout << s << endl;,输出结果变成:abc -2147483636

    这看起来像是一个“玄学”问题,但实际上是因为 未初始化变量导致的未定义行为(Undefined Behavior)


    二、核心问题分析

    1. to_int() 函数中存在未初始化的变量

    int to_int(string s){
        int d;
        for(int i=0; i < s.size(); i++){
            d = d * 10;
            d += s[i] - '0';
        }
        return d;
    }
    

    在这段代码中,d 是一个局部变量,没有被初始化。C++ 不会自动初始化局部变量,因此它的初始值是不确定的(垃圾值)。如果 s 是空字符串,或者包含非数字字符,这段代码的行为就不可预测。

    重点:未初始化的变量会导致未定义行为。


    2. getS() 函数的问题

    string getS(){
        char c = ' ';
        string s = "";
        while(1){
            c = getch();
            if(c != ' ') s = s + c;
            else break;
        }
        return s;
    }
    

    这里有一个小问题:getch() 是从键盘读取一个字符,但它不会读取空格,而是直接返回空格键对应的 ASCII 值(即 ' ')。所以当你按下空格键时,c == ' ' 成立,循环停止。

    但问题在于,getch() 会读取所有按键,包括回车等。如果你在输入过程中按了回车(Enter),它也会被读入 s 中,这可能会影响后续的 to_int() 转换。


    3. getI() 函数中的 cout << s << endl; 的影响

    当你没有打印 s 时,s 的内容可能是不完整的或错误的。但在某些情况下,编译器可能会优化掉未使用的变量,导致 s 实际上未被正确赋值。

    重点:未使用的变量可能导致编译器优化,使得变量内容不一致。


    三、为什么会出现 abc -2147483636

    s"abc" 时,to_int("abc") 会尝试将字母转换为数字,但由于 s[i] - '0' 对于非数字字符来说是无效的,结果会是随机的负数,比如 -2147483636(这是 INT_MIN 的近似值)。

    而当你打印 s(第22行),s 会被正确赋值为 "abc",此时 to_int("abc") 仍然失败,但此时 d 可能因为某些原因(如内存布局)得到了一个特定的值(比如 -2147483636)。


    四、解决方案(修复代码)

    ✅ 修复方案一:初始化变量 d

    int to_int(string s){
        int d = 0; // ✅ 初始化为0
        for(int i = 0; i < s.size(); i++){
            d = d * 10;
            d += s[i] - '0';
        }
        return d;
    }
    

    ✅ 修复方案二:检查字符串是否合法

    int to_int(string s){
        int d = 0;
        for(int i = 0; i < s.size(); i++){
            if(s[i] < '0' || s[i] > '9') {
                return 0; // 或者抛出异常
            }
            d = d * 10;
            d += s[i] - '0';
        }
        return d;
    }
    

    ✅ 修复方案三:改进 getS() 函数,避免读取空格后继续读取

    string getS(){
        char c;
        string s;
        while (true) {
            c = getch();
            if (c == ' ') break; // 遇到空格停止
            s += c;
        }
        return s;
    }
    

    五、最终建议

    1. 始终初始化局部变量
    2. 检查输入合法性,避免非法字符参与运算。
    3. 避免使用 getch(),除非你非常清楚它的行为(尤其是在多平台开发中)。
    4. 使用标准输入函数(如 cin)更安全可靠。

    六、修改后的完整代码示例

    #include <bits/stdc++.h>
    #include <windows.h>
    #include <conio.h>
    using namespace std;
    
    int to_int(string s) {
        int d = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] < '0' || s[i] > '9') return 0; // 非法字符处理
            d = d * 10 + (s[i] - '0');
        }
        return d;
    }
    
    string to_string(int i) {
        if (i == 0) return "0";
        string s;
        while (i) {
            s = char(i % 10 + 48) + s;
            i /= 10;
        }
        return s;
    }
    
    string getS() {
        char c;
        string s;
        while (true) {
            c = getch();
            if (c == ' ') break;
            s += c;
        }
        return s;
    }
    
    int getI() {
        string s = getS();
        cout << s << endl; // ✅ 可以保留,不影响逻辑
        int i = to_int(s);
        return i;
    }
    
    int main() {
        string s1 = getS();
        int a = getI();
        cout << s1 << ' ' << a;
        return 0;
    }
    

    七、总结

    | 问题点 | 解决方式 | |--------|----------| | 未初始化变量 d | ✅ 初始化为 0 | | 非数字字符处理 | ✅ 添加判断 if (s[i] < '0' || s[i] > '9') | | getch() 行为复杂 | ✅ 改用 cin 或更可控的方式 | | 未使用变量 s | ✅ 使用 cout << s 保证变量有效 |


    如有需要,我可以进一步解释 getch()cin 的区别,以及如何在不同平台上实现类似功能。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 8月18日
  • 已采纳回答 8月10日
  • 创建了问题 8月10日