【问题标题】:scanf in Borland C++ BuilderBorland C++ Builder 中的 scanf
【发布时间】:2014-11-20 09:26:41
【问题描述】:

我正在尝试使用函数 scanf 检查我的变量的类型。它适用于 Dev C++(我的输入是 int),但它不使用 Borland。这是我尝试过的:

AnsiString as = Edit1->Text;
string b = as.c_str();

int testb = atoi(b.c_str());

if(scanf("%i", &testb)==1){
do sth;
}

有什么想法吗?

[edit1] 移自 Spektre 的评论

我还有一个问题。我的输入值应该类似于xx-xx-xxxx,所以它是一个日期。
我必须检查日、月和年是否为整数。
我试过这样:

AnsiString a = Edit1->Text;
date = a.c_str();
 if (a==AnsiString().sprintf("%i",atoi(a.SubString(0,2).c_str()))
  && a==AnsiString().sprintf("%i",atoi(a.SubString(3,2).c_str()))
  && a==AnsiString().sprintf("%i",atoi(a.SubString(6,4).c_str())) )
 { 
 //do sth
 }
  • 但它只检查一天。有谁知道为什么? – J.B. 20 小时前

【问题讨论】:

  • 当你说它不起作用时,你是什么意思?当你运行你展示的代码时会发生什么?您是否尝试过在调试器中运行并逐行逐行查看会发生什么?还有为什么要赋值给testb,然后直接覆盖the value with a scanf`调用呢?
  • 你能解释一下这里是如何检查类型的吗?你计算testb,然后在scanf中丢弃它的值。
  • 我需要检查输入值是数字还是字符,因为我需要整数作为输入类型。
  • 要转换字符串并验证字符串确实是整数,请使用例如std::stoi(或者如果你没有,那么std::strtol)。
  • 最好将Edit1输入类型设置为数字,并使用Edit1->Text->ToInt()

标签: c++ scanf c++builder builder borland-c++


【解决方案1】:

你让这件事变得比它应该的要复杂得多。

scanf() 从 STDIN 读取,但 GUI 进程不使用 STDIN 进行输入,这就是它不适合您的原因。请改用sscanf()

int testb;
if (sscanf(AnsiString(Edit1->Text).c_str(), "%d", &testb) == 1)
{
    // do sth ...
}

或者,使用 RTL 的 TryStrToInt() 代替:

int testb;
if (TryStrToInt(Edit1->Text, testb))
{
    // do sth ...
}

至于检查日期字符串,您可以使用sscanf()

int day, month, year;
if (sscanf(AnsiString(Edit1->Text).c_str(), "%2d-%2d-%4d", &day, &month, &year) == 3)
{
    // do sth ...
}

或者使用 RTL 的 TryStrToDate():

TDateTime testb;

TFormatSettings fmt = TFormatSettings::Create();
fmt.DateSeparator = '-';
fmt.ShortDateFormat = "d-m-y";

if (TryStrToDate(Edit1->Text, testb, fmt))
{
    // do sth ...
}

【讨论】:

    【解决方案2】:

    我是这样做的

    AnsiString s=Edit1->Text; // copy to real AnsiString ... the AnsiStrings inside visual components are not the same ... some functions/operations does not work properly for them
    int e,i,l=s.Length();
    
    for(e=0,i=1;i<=l;) 
     {
     e=1; // assume it is integer
     if (s[i]=='-') i++; // skip first minus sign
      for (;i<=l;i++) // scan all the rest 
       if ((s[i]<'0')||(s[i]>'9')) // if not a digit
        { 
        e=0; // then not an integer
        break; // stop
        }
     break;
     }
    // here e holds true/false if s is valid integer
    
    now you can use safely
    if (e) i=s.ToInt(); else i=0;
    
    • 不确定s.ToInt() 是否也有问题,但至少在 BDS2006 之前
    • 如果您调用 s.ToDouble() 获取无效号码,则会引发不可屏蔽的异常
    • 例如,如果您尝试转换 0.98 并且小数点未设置为 . 您的程序崩溃(atoi 和 atof 是安全的)

    你也可以使用 sprintf:

    AnsiString s=Edit1->Text;
    if (s==AnsiString().sprintf("%i",atoi(s.c_str()))) /* valid integer */;
    

    【讨论】:

    • 感谢您的解决方案。它部分有效。我还有一个问题。我的输入值应该看起来像 xx-xx-xxxx 所以它是一个日期。我必须检查日、月和年是否为整数。我试过这样: AnsiString a = Edit1->Text; date = a.c_str() if(a==AnsiString().sprintf("%i",atoi(a.SubString(0,2).c_str())) && a==AnsiString().sprintf(" %i",atoi(a.SubString(3,2).c_str())) && a==AnsiString().sprintf("%i",atoi(a.SubString(6,4).c_str()) ) ){ 做某事} 但它只检查一天。有谁知道为什么?
    • @J.B.有两个原因。 1. 你应该为内部条件添加括号来分隔 && 操作数(有时编译器会用多个条件做有趣的事情,如果没有括号) 2. AnsiString 在旧 VCL(包括 bds2006)上有一个小错误,如果你调用 ...=a.sprintf(...) 或 @ 987654328@ 它还更改了 a 变量(例如,在 BCB5 中这没问题,但在 BCB6 和 BDS2006 中......它被窃听了)要么将子字符串存储到单独的变量中,然后将它们剪切到那里,要么在我的答案中使用第一个选项(在那里你可以用-跳过对for进行硬编码......它看起来也会更好
    • @J.B.还要在断点处检查a.SubString(6,4) 的值,因为AnsiString 索引是从1 开始而不是从0 开始...不应该是a.SubString(7,4)(现在不确定,懒得检查)?
    猜你喜欢
    • 2010-09-25
    • 1970-01-01
    • 2014-12-10
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    相关资源
    最近更新 更多