【问题标题】:fetching string and converting to double获取字符串并转换为双精度
【发布时间】:2016-07-29 14:44:13
【问题描述】:

我正在尝试创建一个函数,该函数可以确定输入是否可以完美转换为双精度,然后能够将其存储到双精度数组中。例如,“12.3a”的输入无效。据我所知,strtod 仍然可以将其转换为 12.3,其余的将存储到指针中。在我的函数 doubleable 中,它过滤输入字符串是否仅包含数字。但是,我知道 double 有“。”就像在“12.3”中一样,我的函数将返回“X”(无效)。

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



char doubleable (char unsure[], int length){
int i;
int flag;
for (i=0; i<length; i++ ){
    if(isdigit(unsure[i]==0)){
        printf("You have invalid input.\n");
        flag=1;
        break;
    }
}
//check for '.' (?)
if(flag==1)
    return 'X';
else
    return 'A';



}

int main(){
char input [10];
double converted[5];
char *ptr;
int i;

for(i=0; i<5; i++){
    fgets(input, 10, stdin);
    //some code here to replace '\n' to '\0' in input
    if(doubleable(input, strlen(input))=='X'){ 
        break;
    }

    converted[i]=strtod(input, &ptr);
    //printf("%lf", converted[i]); 
}
    return 0;
} 

我正在考虑检查“。”的出现。在输入中,以及输入多少(对于像 12.3.12 这样的输入,可以认为是无效的)。我在正确的轨道上吗?还是有更简单的方法来解决这个问题?我还阅读了有关 strtok 函数的信息,在这里会有帮助吗?不过,这个功能对我来说仍然很模糊。

编辑:

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

double HUGE_VAL= 1000000;

void string_cleaner (char *dirty){
int i=0;
while(1){
    if (dirty[i]=='\n'){
        dirty[i]='\0';
        break;
    }
    i++;
}
}

int doubleable2(const char *str)
{
char *end_ptr;
double result;

result = strtod(str, &end_ptr);

if (result == HUGE_VAL || result == 0 && end_ptr == str)
    return 0;  // Could not be converted

if (end_ptr < str + strlen(str))
    return 0;  // Other input in the string after the number

return 1;  // All of the string is part of the number
}

int main(){
char input [10];
double converted[10];
char *ptr;
int i;

for(i=0; i<5; i++){
    while (1){
    printf("Please enter:");
    fgets(input, 10, stdin);
    string_cleaner(input);
    if (doubleable2(input)==0)
        continue;
    else if (doubleable2(input)==1)
        break;
    }
    converted[i]=strtod(input, &ptr);
    printf("%lf\n", converted[i]);
    }
     return 0;
    }

谢谢!它工作得很好!我有一个后续问题。如果我输入的字符串太长,程序就会中断。如果我要将输入限制在 input[] 中最多 9 个字符,我该怎么做?

根据我对 fgets(xx, size, stdin) 的了解,它只能获取 size 个字符(包括 \n、\0),然后将其存储到 xx。在我的程序中,我认为如果将其设置为 10,则不会考虑超过 10 的任何内容。但是,如果我输入一个太长的字符串,我的程序就会中断。

【问题讨论】:

  • 你还应该初始化flag
  • 那里,嗯,它返回一些字符,而不是'X',因为在 main 中,'X' 是唯一重要的控制返回。如果返回不是“X”,则下面的函数将继续。
  • 如果flag的未初始化值为1,函数将始终返回'X'

标签: c fgets strtod


【解决方案1】:

您确实可以使用strtod 并检查返回值和作为第二个参数给出的指针:

int doubleable(const char *str)
{
    const char *end_ptr;
    double result;

    result = strtod(str, &end_ptr);

    if (result == HUGE_VAL || result == 0 && end_ptr == str)
        return 0;  // Could not be converted

    if (end_ptr < str + strlen(str))
        return 0;  // Other input in the string after the number

    return 1;  // All of the string is part of the number
}

请注意,在调用此函数之前,您需要删除fgets 大部分时间添加到字符串中的换行符。

【讨论】:

    【解决方案2】:

    据我所知,strtod 仍然可以将其转换为 12.3,剩下的将存储到指针中。

    这是正确的——请参阅它的man page

    如果 endptr 不为 NULL,则指向转换中使用的最后一个字符之后的字符的指针存储在 endptr 引用的位置。

    所以使用这些信息!

    #include <stdio.h>
    #include <stdbool.h>
    #include <errno.h>
    
    bool doable (const char *buf)
    {
        char *endptr;
    
        errno = 0;
        if (!buf || (strtod (buf, &endptr) == 0 && errno))
            return 0;
        if (*endptr)
            return 0;
        return 1;
    }
    
    int main (void)
    {
        printf ("doable: %d\n", doable ("12.3"));
        printf ("doable: %d\n", doable ("12.3a"));
        printf ("doable: %d\n", doable ("abc"));
        printf ("doable: %d\n", doable (NULL));
        return 0;
    }
    

    结果

    doable: 1
    doable: 0
    doable: 0
    doable: 0
    

    【讨论】:

      【解决方案3】:

      接受回答后

      使用strtod() 是正确的方法,但它有一些挑战

      #include <ctype.h>
      #include <stdlib.h>
      
      int doubleable3(const char *str) {
        if (str == NULL) {
          return 0;  // Test against NULL if desired.
        }
      
        char *end_ptr;  // const char *end_ptr here is a problem in C for strtod()
        double result = strtod(str, &end_ptr);
      
        if (str == end_ptr) {
          return 0;  // No conversion
        }
      
        // Add this if code should accept trailing white-space like a \n
        while (isspace((unsigned char) *endptr)) {
          endptr++;
        }
      
        if (*end_ptr) {
          return 0;  // Text after the last converted character
        }
      
        // Result overflowed or maybe underflowed
        // The underflow case is not defined to set errno - implementation defined.
        // So let code accept all underflow cases
        if (errno) {
          if (fabs(result) == HUGE_VAL) {
            return 0;  // value too large
          }
        }
      
        return 1; // Success
      }
      

      OP的代码

      result == 0result == 0 &amp;&amp; end_ptr == str 中没有值。简化为end_ptr == str

      代替if (end_ptr &lt; str + strlen(str)),一个简单的if (*end_ptr) 就足够了。

      if (result == HUGE_VAL ... 是一个问题有两个原因。 1) 当result == HUGE_VAL 发生在两种情况下:合法转换和溢出转换。需要测试errno 来区分。 2)测试应该是if (fabs(result) == HUGE_VAL ...来处理负数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-11
        • 2011-08-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多