简体   繁体   English

提取字符串并转换为双精度

[英]fetching string and converting to double

I'm trying to create a function which can determine if an input can be converted perfectly into a double and then be able to store it into an array of doubles. 我正在尝试创建一个函数,该函数可以确定输入是否可以完美地转换为双精度,然后将其存储为双精度数组。 For example, an input of "12.3a" is invalid. 例如,输入“ 12.3a”无效。 From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. 据我所知,strtod仍然可以将其转换为12.3,其余的将存储到指针中。 In my function doubleable, it filters whether the input string consists only of digits. 在我的doubleable函数中,它过滤输入字符串是否仅包含数字。 However, I'm aware that double has "." 但是,我知道double具有“。” like in "12.3", and my function will return 'X' (invalid). 就像“ 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;
} 

I'm thinking of something like checking for the occurrence of "." 我正在考虑检查“。”的出现。 in input, and by how much (for inputs like 12.3.12, which can be considered invalid). 输入以及输入的数量(对于12.3.12这样的输入,可以认为是无效的)。 Am I on the right track? 我在正确的轨道上吗? or are there easier ways to get through this? 还是有更简单的方法来解决这个问题? I've also read about the strtok function, will it be helpful here? 我还阅读了有关strtok函数的信息,这对您有帮助吗? That function is still quite vague to me, though. 但是,该功能对我来说仍然很模糊。

EDIT: 编辑:

#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;
    }

thank you! 谢谢! It works just fine! 它很好用! I have a follow up question. 我有一个后续问题。 If I enter a string that is too long, the program breaks. 如果输入的字符串太长,程序将中断。 If I am to limit the input to, let's say, a maximum of 9 characters in input[], how am I to do that? 如果我要限制input []中最多9个字符的输入,我该怎么做?

from what I understand about fgets(xx, size, stdin), it only gets up to size characters (including \\n, \\0), and then stores it to xx. 根据我对fgets(xx,size,stdin)的了解,它只会放大到大小字符(包括\\ n,\\ 0),然后将其存储到xx。 In my program, I thought if I set it to 10, anything beyond 10 will not be considered. 在我的程序中,我认为如果将其设置为10,则不会考虑超过10的任何内容。 However, if I input a string that is too long, my program breaks. 但是,如果输入的字符串太长,程序将中断。

You can indeed use strtod and check the returned value and the pointer given as the second argument: 您确实可以使用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
}

Note that you need to remove the newline that fgets most of the time adds to the string before calling this function. 请注意,在调用此函数之前,您需要删除大多数情况下fgets添加到字符串的换行符。

From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. 据我所知,strtod仍然可以将其转换为12.3,其余的将存储到指针中。

That is correct – see its man page : 没错-参见其man

If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr . 如果endptr不为NULL,则指向转换中使用的最后一个字符之后的字符的指针存储在endptr引用的位置。

So use that information! 因此,请使用该信息!

#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;
}

results in 结果是

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

After accept answer 接受答案后

Using strtod() is the right approach, but it has some challenges 使用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's code OP的代码

No value with result == 0 in result == 0 && end_ptr == str . result == 0 result == 0 && end_ptr == str没有值。 Simplify to end_ptr == str . 简化为end_ptr == str

Instead of if (end_ptr < str + strlen(str)) , a simple if (*end_ptr) is sufficient. 代替if (end_ptr < str + strlen(str)) ,一个简单的if (*end_ptr)就足够了。

if (result == HUGE_VAL ... is a problem for 2 reasons. 1) When result == HUGE_VAL happens in 2 situations: A legitimate conversion and an overflow conversion. if (result == HUGE_VAL ...是有两个原因的问题。1)当result == HUGE_VAL在两种情况下发生时:合法转换和溢出转换。 Need to test errno to tell the difference. 需要测试errno才能分辨出差异。 2) the test should be if (fabs(result) == HUGE_VAL ... to handle negative numbers. 2)测试应为if (fabs(result) == HUGE_VAL ...以处理负数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM