Convertir cadena, flotar (sin atof) en C

Estoy diseñando una función que convertirá una cadena en un flotador. por ejemplo, “45.5” = 45.5

Tengo esto hasta ahora. Pero no parece funcionar. Tenga en cuenta que no podemos usar ninguna función de la biblioteca de C como atoi, atof o incluso pow para esa materia.

int str2float( char *s ) { int num = 0; int dec = 0; double i = 1.0; int ten = 1; /***** ADD YOUR CODE HERE *****/ for(; *s != '\0'; s++) { if (*s == '.'){ for(; *s != '\0'; s++){ dec = (dec * CONT) + (*s - '0'); i++; } }else{ num = (num * CONT) + (*s - '0'); } } for(;i!=0;i--){ ten *= 10; } dec = dec / (ten); printf("%d", dec); num += dec; return num; } 

Aquí está mi bash:

 float stof(const char* s){ float rez = 0, fact = 1; if (*s == '-'){ s++; fact = -1; }; for (int point_seen = 0; *s; s++){ if (*s == '.'){ point_seen = 1; continue; }; int d = *s - '0'; if (d >= 0 && d <= 9){ if (point_seen) fact /= 10.0f; rez = rez * 10.0f + (float)d; }; }; return rez * fact; }; 

Un problema potencial es que s es incrementado por el bucle externo antes de verificar que no está apuntando al terminador NULL.

 for(; *s != '\0'; s++) { ... for(; *s != '\0'; s++){ ... } // inner loop is done now since we have *s=='\0' ... ... // ... but now we're going to increment s again at the end of the outer loop! } 

Debe salir del bucle interno y externo inmediatamente después de detectar el terminador NULL.

Esta es mi solución para la función.

 #include float my_a2f(char *); main() { char ch[20]; float i; printf("\n enter the number as a string\n"); scanf("%[^\n]", ch); i = my_a2f(ch); printf(" string =%s , float =%g \n", ch, i); } float my_a2f(char *p) { // here i took another two variables for counting the number of digits in mantissa int i, num = 0, num2 = 0, pnt_seen = 0, x = 0, y = 1; float f1, f2, f3; for (i = 0; p[i]; i++) if (p[i] == '.') { pnt_seen = i; break; } for (i = 0; p[i]; i++) { if (i < pnt_seen) num = num * 10 + (p[i] - 48); else if (i == pnt_seen) continue; else { num2 = num2 * 10 + (p[i] - 48); ++x; } } // it takes 10 if it has 1 digit ,100 if it has 2 digits in mantissa for (i = 1; i <= x; i++) y = y * 10; f2 = num2 / (float) y; f3 = num + f2; return f3; } 

algo como esto debería hacerlo:

 float str2float(char* s){ // solve for special cases where s begins with 0's or nun numeric values, or if s is NULL float result = 0; int decimalCount = 0, i = 0, decimalPointLoc = strlen(s); for (; s[i] != '\0'; i++){ if (s[i] == '.') decimalPointLoc = i; if (i < decimalPointLoc) { result *= 10; result += (int)(s[i] + '0'); } else { result += (float)(s[i] + '0')/(pow(i-decimalPointLoc,10)); } } return result; } 

El código puede no ser muy limpio y no necesariamente la mejor manera de hacerlo, pero entiendes la idea. pow (x, y) devuelve x ^ y y requiere math.hy strlen (s) devuelve el tamaño de s y requiere string.h.

 double Myatof(char str[]){ int len=0, n=0,i=0; float f=1.0,val=0.0; //counting length of String while(str[len])len++; //cheking for valid string if(!len)return 0; //Extracting Integer part while(i 
 #define ZERO 48 #define NINE 57 #define MINUS 45 #define DECPNT 46 int strtoint_n(char* str, int n) { int sign = 1; int place = 1; int ret = 0; int i; for (i = n-1; i >= 0; i--, place *= 10) { int c = str[i]; switch (c) { case MINUS: if (i == 0) sign = -1; else return -1; break; default: if (c >= ZERO && c <= NINE) ret += (c - ZERO) * place; else return -1; } } return sign * ret; } float _float_fraction(char* str, int n) { float place = 0.1f; float ret = 0.0f; int i; for (i = 0; i < n; i++, place /= 10) { int c = str[i]; ret += (c - ZERO) * place; } return ret; } float strtoflt(char* str) { int n = 0; int sign = 1; int d = -1; int ret = 0; char* temp = str; while (*temp != '\0') { switch (*temp) { case MINUS: if (n == 0) sign = -1; else return -1; break; case DECPNT: if (d == -1) d = n; else return -1; break; default: if (*temp < ZERO && *temp > NINE) return -1; } n++; temp++; } if (d == -1) { return (float)(strtoint_n(str, n)); } else if (d == 0) { return _float_fraction((str+d+1), (nd-1)); } else if (sign == -1 && d == 1) { return (-1)*_float_fraction((str+d+1), (nd-1)); } else if (sign == -1) { ret = strtoint_n(str+1, d-1); return (-1) * (ret + _float_fraction((str+d+1), (nd-1))); } else { ret = strtoint_n(str, d); return ret + _float_fraction((str+d+1), (nd-1)); } } 

Creo que mi solución es más robusta.

Siéntete libre de desafiar mi código. Aquí está el enlace: https://github.com/loverszhaokai/Demo/blob/master/str_to_float/src/str_to_float.cc

El siguiente es el código:

 #include  #include  #include  #include  #include  #include  #include  using namespace std; int last_err_code = 0; // last_err_code = 0 when there is no error // // last_err_code = 1 when there is invalid characters, the valid characters // are 0~9, '.', '+-' // // last_err_code = 2 when there is no integer before '.' or there is no integer // after '.' // eg ".123", "123.", "." // // last_err_code = 3 when there is more than one '.' // eg "123..456", "123.4.56" // // last_err_code = 4 when the integer is bigger than FLOAT_MAX // eg "1111111111111111111111111111111111111.23" // // Clear the left and right whitespace // eg " 123 456 " -> "123 456" char *trim(char *str) { while (*str == ' ' || *str == '\t') str++; char *start = str; if (!(*str)) return str; char *end = str; while (*str) { if (*str != ' ' && *str != '\t') end = str; str++; } *(end + 1) = 0; return start; } // String to Float float str_to_float(const char *pstr) { char *pstr_copy, *str; // The sign of float, set -1 when the first character is '-' int sign = 1; // The value of integers long long integer = 0; // The value of decimals double decimal = 0; // The multiple of next decimal double dec_num = 0.1; // Has found dot '.' bool has_dot = 0; // Has integer bool has_integer = 0; if (pstr == NULL) return 0; pstr_copy = strdup(pstr); str = trim(pstr_copy); if (!(*str)) { // " " return 0; } if (*str == '+' || *str == '-') { if (*str == '-') sign = -1; str++; } while (*str) { if (*str >= '0' && *str <= '9') { if (!has_dot) { // "123" if (!has_integer) has_integer = 1; integer *= 10; integer += *str - '0'; if (integer > (long long)INT_MAX) { // eg "111111111111111111111111111111111.22" last_err_code = 4; return 0; } } else if (!has_integer) { // ".123" last_err_code = 2; return 0; } else { // "123.456" if (dec_num < (double)1e-10) { // There are too many decimals, ignore the following decimals } else { decimal += (*str - '0') * dec_num; dec_num *= 0.1; } } } else if (*str == '.') { if (has_dot) { // eg "123...456" last_err_code = 3; return 0; } has_dot = 1; } else { // eg "123fgh?.456" last_err_code = 1; return 0; } str++; } if (has_dot && (!has_integer || dec_num == 0.1)) { // eg ".123" or "123." or "." last_err_code = 2; return 0; } free(pstr_copy); float ret = (float) integer + (float)decimal; return ret * sign; } int main() { const struct TestCase { const char *str; const float ret; int last_err_code; } test_cases[] = { // last_err_code != 0 { "abc", 0, 1 }, { "123+.456", 0, 1 }, { "++123.456", 0, 1 }, { ".", 0, 2 }, { ".123", 0, 2 }, { "123.", 0, 2 }, { "123..456", 0, 3 }, { "123.4.56", 0, 3 }, // Case #8: { "1111111111111111111111111111111.456", 0, 4 }, // last_err_code == 0 { "", 0, 0 }, { "123.456", 123.456, 0 }, // There are too many decimals { "1.12345678901234567890", 1.12345678, 0 }, }; int errors = 0; for (int iii = 0; iii < sizeof(test_cases) / sizeof(TestCase); iii++) { const TestCase &tc = test_cases[iii]; // Clear last_err_code last_err_code = 0; const float actual_ret = str_to_float(tc.str); if (tc.ret != actual_ret || last_err_code != tc.last_err_code) { errors++; cout << "Case #" << iii << ": FAILED" << endl; cout << "\tExpected ret=" << tc.ret << endl; cout << "\tAcutal ret=" << actual_ret << endl; cout << "\tExpected last_err_code=" << tc.last_err_code << endl; cout << "\tAcutal last_err_code=" << last_err_code << endl; } } if (errors == 0) cout << "All test passed!" << endl; else cout << "There are " << errors << " cases failed." << endl; return 0; } 
 #include #include float myAtoF(char *); //int myAtoI(char); void main(int argc,char **argv) { float res; char str[10]; if(argc<2) { printf("Supply a floating point Data\n"); return; } printf("argv[1] = %s\n",argv[1]); // strcpy(str,argv[1]); // printf("str = %s\n",str); res=myAtoF(argv[1]); printf("Res = %f\n",res); } float myAtoF(char *str) { printf("str = %s\n",str); int i,sum,total,index; float res; if(!strchr(str,'.')) { printf("Supply only real Data\n"); return ; } i=0; while(str[i]) { if(!str[i]>='0'&&str[i]<='9') { printf("Wrong Data Supplied\n"); return; } if(str[i]=='.') { index=i; i++; continue; } total=str[i]-48; if(i==0) { sum=total; i++; continue; } sum=sum*10+total; i++; } printf("Integer Data : %d\n",sum); index=(strlen(str)-1)-index; printf("index : %d\n",index); res=sum; for(i=1;i<=index;i++) { res=(float)res/10; } return res; } 
 double atof(char* num) { if (!num || !*num) return 0; double integerPart = 0; double fractionPart = 0; int divisorForFraction = 1; int sign = 1; bool inFraction = false; /*Take care of +/- sign*/ if (*num == '-') { ++num; sign = -1; } else if (*num == '+') { ++num; } while (*num != '\0') { if (*num >= '0' && *num <= '9') { if (inFraction) { /*See how are we converting a character to integer*/ fractionPart = fractionPart*10 + (*num - '0'); divisorForFraction *= 10; } else { integerPart = integerPart*10 + (*num - '0'); } } else if (*num == '.') { if (inFraction) return sign * (integerPart + fractionPart/divisorForFraction); else inFraction = true; } else { return sign * (integerPart + fractionPart/divisorForFraction); } ++num; } return sign * (integerPart + fractionPart/divisorForFraction); } 

Mi solución:

 float str2float (const char * str) { unsigned char abc; float ret = 0, fac = 1; for (abc = 9; abc & 1; str++) { abc = *str == '-' ? (abc & 6 ? abc & 14 : (abc & 47) | 36) : *str == '+' ? (abc & 6 ? abc & 14 : (abc & 15) | 4) : *str > 47 && *str < 58 ? abc | 18 : (abc & 8) && *str == '.' ? (abc & 39) | 2 : !(abc & 2) && (*str == ' ' || *str == '\t') ? (abc & 47) | 1 : abc & 46; if (abc & 16) { ret = abc & 8 ? *str - 48 + ret * 10 : (*str - 48) / (fac *= 10) + ret; } } return abc & 32 ? -ret : ret; } 

Pruébalo

 printf("%f\n", str2float("234.3432435543")); // 234.343246 printf("%f\n", str2float("+234.3432435543")); // 234.343246 printf("%f\n", str2float("-234.3432435543")); // -234.343246 printf("%f\n", str2float(" + 234.3432435543")); // 234.343246 printf("%f\n", str2float(".5")); // 0.500000 printf("%f\n", str2float("- .5")); // -0.500000 

Por cierto, en caso de que alguien lo necesite, aquí está también mi solución para convertir una cadena en un entero :

 int str2int (const char *str) { unsigned char abc; int ret = 0; for (abc = 1; abc & 1; str++) { abc = *str == '-' ? (abc & 6 ? abc & 6 : (abc & 23) | 20) : *str == '+' ? (abc & 6 ? abc & 6 : (abc & 7) | 4) : *str > 47 && *str < 58 ? abc | 10 : !(abc & 2) && (*str == ' ' || *str == '\t') ? (abc & 23) | 1 : abc & 22; if (abc & 8) { ret = ret * 10 + *str - 48; } } return abc & 16 ? -ret : ret; } 
 #include  #include  #include double myatof(char *num); int main(void) { double res;char str[15]; printf("enter a number in the form of a string:\n"); gets(str); res=myatof(str); printf("Float representation of above number is %f\n",res); return 0; } double myatof(char *str) { int i=0;int len1,len2,j; float num=0.0;float num1=0.0; float num2=0.0; do { if((str[i++]=='.')) { len1=i-1;len2=-((strlen(str)-1)-(i-1)); for(int p=0,q=(len1-1);p=0;p++,q--) { num1+=((str[p]-'0')*pow(10,q)); } for(int r=len1+1,s=-1;r=len2;r++,s--) { num2+=((str[r]-'0')*pow(10,s)); } } }while(str[i]!='\0'); num=num1+num2; printf("%f\t",num1); printf("%f\t",num2); return num; }