在C中将字符串转换为整数的递归函数

Recursive function to convert string to integer in C

我有以下工作代码;它接受一个字符串输入作为函数参数,并吐出转换为十进制的相同字符串。

我不打算考虑负输入,尽管我知道当第一个索引字符是“-”时我可以将布尔标志设置为 true。如果标志切换为 true,则取总输出并乘以 -1。

无论如何,我很困惑从这里去哪里;我想调整我的代码,以便我可以计算小数位。乘以 10 并加上下一个数字(在将该数字从 ASCII 值转换后)生成一个整数,该整数在输出中以十进制显示。这显然不适用于小于 1 的数字。我理解为什么(但不是真正如何)确定小数点在哪里并说 "for anything AFTER this string index containing a decimal point, do this differently")。另外,我知道不是乘以 10 的幂并加上下一个数字,而是必须乘以 -10 的因数,但我不确定这如何适合我现有的代码...

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

int num = 0;

int finalValue(char *string1) {

    int i = 0;

    if (string1[i] != '[=10=]') {

        if (string1[i]<'0' || string1[i]>'9') {
            printf("Sorry, we can't convert this to an integer\n\n");
        }

        else {
            num *= 10;
            num += string1[i] - '0';

            //don't bother using a 'for' loop because recursion is already sort-of a for loop

            finalValue(&string1[i+1]);
        }
    }
    return num;
}

int main(int argc, const char * argv[]) {
    printf("string to integer conversion yields %i\n",(finalValue("99256")));
    return 0;
} 

我对上面的代码做了一些调整,并且可以运行,但是当涉及到小数部分时,它有点难看。出于某种原因,实际的整数输出总是高于输入的字符串……某处数学错误。我通过从最终 return 值中减去一个静态量(并手动乘以 10 的另一个负幂)来解释这一点......我想避免这样做,所以任何人都可以看到我的数学/控制在哪里流量出问题了?

#include <stdio.h>
#include <string.h>
//here we are setting up a boolean flag and two variables
#define TRUE 1
#define FALSE 0
double num = 0;
double dec = 0.0;
int flag = 0;
double final = 0.0;
double pow(double x, double y);


    //we declare our function that will output a DOUBLE
double finalValue(char *string1) {
    //we have a variable final that we will return, which is just a combination of the >1 and <1 parts of the float.

    //i and j are counters
    int i = 0;
    int j = 0;

    //this will go through the string until it comes across the null value at the very end of the string, which is always present in C.
    if (string1[i] != '[=11=]') {

        //as long as the current value of i isn't 'null', this code will run. It tests to see if a flag is true. If it isn't true, skip this and keep going. Once the flag is set to TRUE in the else statement below, this code will continue to run so that we can properly convert the decimal characers to floats.
        if (flag == TRUE) {
        dec += ((string1[i] - '0') * pow(10,-j));
        j++;
        finalValue(&string1[i+1]);
    }

        //this will be the first code to execute. It converts the characters to the left of the decimal (greater than 1) to an integer. Then it adds it to the 'num' global variable.
        else {
            num *= 10;
            num += string1[i] - '0';


            // This else statement will continue to run until it comes across a decimal point. The code below has been written to detect the decimal point and change the boolean flag to TRUE when it finds it. This is so that we can isolate the right part of the decimal and treat it differently (mathematically speaking). The ASCII value of a '.' is 46.
            //Once the flag has been set to true, this else statement will no longer execute. The control flow will return to the top of the function, and the if statement saying "if the flag is TRUE, execute this' will be the only code to run.
            if (string1[i+1] == '.'){
                flag = TRUE;
            }

            //while this code block is running (before the flag is set to true) use recursion to keep converting characters into integers
            finalValue(&string1[i+1]);
        }
    }
    else {
        final = num + dec;
        return final;
    }
    return final;
}

int main(int argc, const char * argv[]) {
    printf("string to integer conversion yields %.2f\n",(finalValue("234.89")));
    return 0;
}

同时跟踪小数点的出现。

int num = 0;
const char *dp = NULL;
int dp_offset = 0;

int finalValue(const char *string1) {
  int i = 0;
  if (string1[i] != '[=10=]') {
      if (string1[i]<'0' || string1[i]>'9') {
        if (dp == NULL && string1[i] == '.') {
          dp = string1;
          finalValue(&string1[i+1]);
        } else {
          printf("Sorry, we can't convert this to an integer\n\n");
        } else {
      } else {
        num *= 10;
        num += string1[i] - '0';
        finalValue(&string1[i+1]);
      }
  } else if (dp) {
     dp_offset = string1 - dp;
  }
  return num;
}

调用finalValue()代码后可以使用dp_offset的值来调整return的值。由于此工作可能是完整浮点转换的开始,因此 dp_offset 的值可以在开始应用于尾数之前添加到指数。

Consider simplification
//int i = 0;
//if (string1[i] ...
if (*string1 ...

注意:在此处使用递归来查找 int 的字符串是一种有问题的方法,尤其是因为它使用全局变量来完成工作。一个简单的功能就足够了。类似未经测试的代码:

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

long long fp_parse(const char *s, int *dp_offset) {
  int dp = '.';
  const char *dp_ptr = NULL;
  long long sum = 0;
  for (;;) {
    if (*s >= '0' && *s <= '9') {
      sum = sum * 10 + *s - '0';
    } else if (*s == dp) {
      dp_ptr = s;
    } else if (*s) {
      perror("Unexpected character");
      break;
    } else {
      break;
    }
    s++;
  }
  *dp_offset = dp_ptr ? (s - dp_ptr -1) : 0;
  return sum;
}

想通了:

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

//here we are setting up a boolean flag and two variables
#define TRUE 1
#define FALSE 0
double num = 0;
double dec = 0.0;
int flag = 0;
double final = 0.0;
double pow(double x, double y);
int j = 1;



    //we declare our function that will output a DOUBLE
double finalValue(char *string1) {

        //i is a counter
    int i = 0;

    //this will go through the string until it comes across the null value at the very end of the string, which is always present in C.
    if (string1[i] != '[=10=]') {
        double newGuy = string1[i] - 48;
        //as long as the current value of i isn't 'null', this code will run. It tests to see if a flag is true. If it isn't true, skip this and keep going. Once the flag is set to TRUE in the else statement below, this code will continue to run so that we can properly convert the decimal characers to floats.
        if (flag == TRUE) {
            newGuy = newGuy * pow(10,(j)*-1);
            dec += newGuy;
            j++;
            finalValue(&string1[i+1]);
        }


        //this will be the first code to execute. It converts the characters to the left of the decimal (greater than 1) to an integer. Then it adds it to the 'num' global variable.
        else {
            num *= 10;
            num += string1[i] - '0';


            // This else statement will continue to run until it comes across a decimal point. The code below has been written to detect the decimal point and change the boolean flag to TRUE when it finds it. This is so that we can isolate the right part of the decimal and treat it differently (mathematically speaking). The ASCII value of a '.' is 46.
            //Once the flag has been set to true, this else statement will no longer execute. The control flow will return to the top of the function, and the if statement saying "if the flag is TRUE, execute this' will be the only code to run.
            if (string1[i+1] == 46){
                flag = TRUE;
                finalValue(&string1[i+2]);
            }

            //while this code block is running (before the flag is set to true) use recursion to keep converting characters into integers
            finalValue(&string1[i+1]);
        }
    }
    else {

        final = num + dec;
        return final;
    }
    return final;
}

int main(int argc, const char * argv[]) {
    printf("string to integer conversion yields %.2f\n",(finalValue("234.89")));
    return 0;
}

我看到你已经使用全局变量正确地实现了它。这行得通,但这里有一个关于如何避免全局变量的想法。

一个非常标准的做法是向递归函数添加参数:

double finalValue_recursive(char *string, int flag1, int data2)
{
    ...
}

然后将带有附加参数的递归函数包装到另一个函数中:

double finalValue(char *string)
{
    return finalValue_recursive(string, 0, 0);
}

使用这个模板代码,可以这样实现(貌似只需要多一个参数):

double finalValue_recursive(char *s, int pow10)
{
    if (*s == '[=12=]') // end of line
    {
        return 0;
    }
    else if (*s == '-') // leading minus sign; I assume pow10 is 0 here
    {
        return -finalValue_recursive(s + 1, 0);
    }
    else if (*s == '.')
    {
        return finalValue_recursive(s + 1, -1);
    }
    else if (pow10 == 0) // decoding the integer part
    {
        int digit = *s - '0';
        return finalValue_recursive(s + 1, 0) * 10 + digit;
    }
    else // decoding the fractional part
    {
        int digit = *s - '0';
        return finalValue_recursive(s + 1, pow10 - 1) + digit * pow(10.0, pow10);
    }
}

double finalValue(char *string)
{
    return finalValue_recursive(string, 0);
}