2016-04-08 8 views
0

Я пытаюсь создать функцию, которая может определить, может ли вход быть преобразован в в двойное, а затем сможет хранить его в массиве удвоений. Например, ввод «12.3a» недействителен. Из того, что я знаю, strtod все равно может преобразовать его в 12.3, а остальные будут сохранены в указатель. В моей функции doubleable она фильтрует, состоит ли входная строка только цифр. Тем не менее, я знаю, что у double есть "." как в «12.3», и моя функция вернет «X» (недействительно).выборка строки и преобразование в double

#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, будет ли это полезно здесь? Однако эта функция все еще довольно расплывчата.

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

спасибо! Он работает отлично! У меня есть следующий вопрос. Если я ввешу слишком длинную строку, программа сломается. Если я ограничу вход, допустим, не более 9 символов ввода [], как мне это сделать?

Из того, что я понимаю о fgets (xx, size, stdin), он получает только символы размера (включая \ n, \ 0), а затем сохраняет его в xx. В моей программе я подумал, что если я установил ее на 10, то ничего более 10 не будет рассмотрено. Однако, если я вводил слишком длинную строку, моя программа прерывается.

+0

Вы также должны инициализировать флаг '. – mch

+0

Там, ну, он возвращает некоторый символ, отличный от «X», потому что в основном «Х» является единственным важным управляющим возвратом. Функция ниже выполняется, если возврат не «X». –

+0

, если неинициализированное значение 'flag' равно' 1', функция всегда будет возвращать '' X''. – mch

ответ

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 большую часть времени добавляет к строке перед вызовом эта функция.

0

Из того, что я знаю, 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 
0

После ответа принять

Использование 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 == 0 в result == 0 && end_ptr == str. Упростить до end_ptr == str.

Вместо if (end_ptr < str + strlen(str)) достаточно простого if (*end_ptr).

if (result == HUGE_VAL ... является проблемой по двум причинам. 1) Когда result == HUGE_VAL происходит в двух ситуациях: законное преобразование и преобразование переполнения. Вам нужно проверить errno, чтобы сказать разницу. 2) тест должен быть if (fabs(result) == HUGE_VAL ... для обработки отрицательных чисел.