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
вместо того, чтобы обрабатывать большие шестнадцатеричные числа.