C++ мне нужно написать функцию, которая преобразует шестнадцатеричный в десятичный и использует рекурсию, и я продолжаю получать ошибки выполнения

Это для класса, поэтому он должен использовать рекурсию, я написал рабочий код итеративно, но я не могу заставить его работать в рекурсии, и я действительно потерян. Я работаю над этим уже неделю. Любые указания или предложения были бы чрезвычайно полезны.

Это моя функция, мне нужно взять шестнадцатеричный как указатель char и вывести его соответствующий десятичный. Я постоянно получаю либо переполнение стека или выделение памяти во время выполнения ошибки, может ли кто-нибудь определить, что не так, и направить меня в правильном направлении?

 int hexToDecimal(const char *hex, int offset, int power){
  if(offset >= 0){
    hexChar = *(hex+offset);

    if( isalpha(hexChar) ) {
      hexChar = toupper(hexChar);
      hexNum = hexChar - asciiCharOffset;
    } else { 
      hexNum = hexChar - asciiIntOffset;
    }   
    return hexToDecimal(hex, offset--, power++) +  hexNum * (int)pow(16,power); 

  } else {
    return 0;
  }
}

5 ответов


Я не скомпилировал его, но с первого взгляда говорит мне, что соответствующая строка должна быть:

return hexToDecimal(hex, offset-1, power+1) +  hexNum * (int) pow(16,power-1);    

потому что в вашем случае вы называете себя ad infinitum (вызывается, скажем, offset 6, Если вы передадите offset-он все равно пройдет 6, потому что он уменьшится после того, как он даст значение функции).

кроме того, пост-инкремент даст вам неопределенное поведение для вызова pow(16,power) позже в том же выражении, потому что (взяв пример power=6 снова), это может быть pow(16,6) или pow(16,7) в зависимости от компилятора.

все это в стороне, есть также риск, что pow() даст вам ложное (округленное вниз) значение при преобразовании в int (может оказаться, что pow(16,2) возвращает 255.9999999, и вы получите (int)255, здесь достаточно доказательств и решений на stackoverflow, просто найдите pow).

EDIT (в ответ на комментарии):

наконец, представляем волшебный отладчик printf:

int hexToDecimal(const char *hex, int offset, int power){
  if(offset >= 0){
    char hexChar = *(hex+offset);
    int hexNum, 
        recursed;

    if( isalpha(hexChar) ) {
      hexChar = toupper(hexChar);
      hexNum = hexChar - asciiCharOffset;
    } 
    else { 
      hexNum = hexChar - asciiIntOffset;
    }   
    recursed= hexToDecimal(hexNum, offset-1, power+1); 

    printf("%d + %d * %d\n", recursed, hexNum, (int)pow(16,power-1));

    return recursed +  hexNum * (int)pow(16,power-1); 

  } else {
     return 0;
  }
}

вы используете пост-инкремент здесь:

  return hexToDecimal(hex, offset--, power++) 

Post-increment (и post-decrement) увеличит/уменьшит переменную (т. е. она будет фактически изменить offset и power), но inc/dec произойдет после переменная вычисляется.

то есть:

int i = 5;
std::cout << "i = " << i;     // prints 'i = 5'
std::cout << "\ni = " << i++; // still prints 'i = 5' and then changes i to be 6
std::cout << "\ni = " << i;   // prints 'i = 6'

вы на самом деле не хотите изменять offset и power -- вы хотите передать другое значение для них следующему hexToDecimal вызов.

вы можете поймать такие ошибки, если вы сделаете параметры метода const, то есть:

int hexToDecimal(const char*hex, const int offset, const int power);

я рекомендую сделать параметры const когда у вас нет намерения изменить их. Таким образом, компилятор может помочь вам поймать много распространенных ошибок.


используйте predecrement в аргументе функции. Используйте --offset в аргументе. если u использовать offset--, то в функцию передается начальное значение offset, а затем offset уменьшается.


вот один, который я написал давным-давно... Это, вероятно, не самый лучший или быстрый подход и может использовать некоторую проверку ошибок, но я оставлю это в качестве упражнения для читателя...

    long GetValue(const char *pszStrVal)
    {
      long Retval = 0;
      try {
        char *p = (char*)pszStrVal;
        if(p == NULL) return 0;

        if(strstr(p, "0x")) {
            p++;p++;
            long x = strlen(p);
            long pval = 1 << ((x-1)*4);

            for(int y = 0;y < x;y++,pval = (pval >> 4))
            {
                int digit = 0;
                switch(p[y])
                {
                case 'A':
                case 'a':
                    digit = 10;
                    break;
                case 'B':
                case 'b':
                    digit = 11;
                    break;
                case 'C':
                case 'c':
                    digit = 12;
                    break;
                case 'D':
                case 'd':
                    digit = 13;
                    break;
                case 'E':
                case 'e':
                    digit = 14;
                    break;
                case 'F':
                case 'f':
                    digit = 15;
                    break;
                default:
                    digit = p[y] - 0x30;
                }

                Retval += (pval * digit);
            }
        } else {
            Retval = atoi(p);
        }
    }
    catch(...)
    {
        Retval = 0;
    }
    return Retval;
}

вот простое решение, которое использует второй рекурсивный вызов функции. Надеюсь, это поможет вам отладить ваш:

#include <stdio.h>
#include <ctype.h>

int h2d_rec(const char *hex, int d);

int h2d(const char *hex) {
    return h2d_rec(hex, 0);
}

int h2d_rec(const char *hex, int d) {
    char hexChar = *hex;
    if (0==hexChar) {
        return d;
    }
    int charNum;
    if (isalpha(hexChar)) {
        charNum = 10 + toupper(hexChar) - 'A';
    } else {
        charNum = hexChar - '0';
    }
    // Note d<<4 is the same as 16*d
    return h2d_rec(hex+1, (d<<4) + charNum);
}

int main(int argc, const char **argv) {
    const char *hex = "FF";

    if (1<argc) {
        hex = argv[1];
    }
    printf("%s in decimal is %d\n", hex, h2d(hex));
}

вы можете использовать long вместо того, чтобы обрабатывать большие шестнадцатеричные числа.