将数字从基数转换为另一个基数时的分段错误

时间:2016-09-10 18:50:10

标签: c gcc segmentation-fault

我正在用C编写程序,将数字从任何基数转换为任何基数。它从十进制到任何基础工作但是当我从任何基础实现转换时,我得到分段错误:我必须指定我不使用IDE,只是gcc命令将我的程序链接到静态库。奇怪的是,我尝试在Windows上编译,但它确实有效。有人可以帮助我吗?

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> //library for isdigit
#include <string.h>
#include "ylantron.h" //<-- my library

#define MAX_SYMBOLS 36

void pause();
char* convert(char* value, int startingBase, int endingBase);
char* swapArray(char *oldArray);

// MAIN

int main(int argc, char *argv[]){

/* CHECK ARGUMENTS NUMBER */
if (argc != 4 ){
  printf("\n\e[91m[X]\e[39m Invalid number argument\n");
  pause();
  return 1;
}

/* CHECK ARGUMENTS */
if (   (isdigit(argv[1][0])==0)   ||   (isdigit(argv[2][0])==0)   ||   (isdigit(argv[3][0])==0)   ){
  printf("\n\e[91m[X]\e[39m One of the arguments is not a number\n");
  pause();
  return 1;
}

/* CHECKING BASES */
int check=0;
char *baseType=(char*)calloc(9,sizeof(char));
char *infSup=(char*)calloc(10,sizeof(char));
int numMinMax;

if (atoi(argv[1])<2)   { strcpy(baseType,"starting");   strcpy(infSup,"inferior");   numMinMax=2;   check=1; }
else if (atoi(argv[1])>MAX_SYMBOLS)   { strcpy(baseType,"starting");   strcpy(infSup,"superior");   numMinMax=MAX_SYMBOLS;   check=1; }
else if (atoi(argv[3])<2)   { strcpy(baseType,"ending");   strcpy(infSup,"inferior");   numMinMax=2;   check=1; }
else if (atoi(argv[3])>MAX_SYMBOLS)   { strcpy(baseType,"ending");   strcpy(infSup,"superior");   numMinMax=MAX_SYMBOLS;   check=1; }

if (check==1){
  printf("\n\e[91m[X]\e[39m The %s base can't be %s to %d\n",   baseType,   infSup,   numMinMax);

  free(baseType);
  free(infSup);

  pause();
  return 1; }

int base_from, base_to;
char* val;

base_from=atoi(argv[1]);
val=argv[2];
base_to=atoi(argv[3]);

if (base_from==base_to)   { printf("\n\e[93m[?]\e[39m Why you want me to convert a number with equal bases?"); pause(); return 1; }

printf("\nThe result is %s\n\n",converti(val,base_from,base_to));

return 0;
}

// FUNCTIONS

void pause() {

printf("\nPress any key...");
getch();
printf("\n");

}


char* convert(char* value, int startingBase, int endingBase){

char symbols[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
char *valueArray=NULL;
int val=0;


if (startingBase != 10 ){
  for (int i=0;i<(strlen(value)/sizeof(char));i++){
     for (int j=0;j<MAX_SYMBOLS;j++){
        if (value[i]==symbols[j]){
           val+=j;
           break;
        }
     }
  }
}

printf("val: %d",val);

for (int i=1;val!=0;){
  valueArray=(char *)realloc(valueArray,(++i)*sizeof(char));
  valueArray[i-2]=symbols[(val%endingBase)];
  valueArray[i-1]='\0';
  val/=endingBase;
}

swapArray(valueArray);

return valueArray;

}

char* swapArray(char *oldArray){

char old;
int i,j;

for (i=0,j=strlen(oldArray)-1;i<(strlen(oldArray)/2);i++,j--){
  old=oldArray[i];
  oldArray[i]=oldArray[j];
  oldArray[j]=old;
}

return oldArray;
}

1 个答案:

答案 0 :(得分:2)

你有一些真正的错误。有些会产生崩溃。其他人会产生错误的结果。首先,我将解释这些错误。

此外,我在下面制作了两个版本的程序。一个注释注释显示错误[有修复]。并且,第二个清理版本。

对于崩溃,倒退:

  1. swapArray是segfaulting,因为它被赋予NULL指针
  2. convertswapArray(valueArray)valueArray可以/ NULL
  3. convert中,如果valueArray为零,则NULLval(即)realloc的循环将为零迭代
  4. val如果startingBase为10,则可能为零(即)前两个循环不会被执行
  5. 这两个循环应始终执行(即)if (startingBase != 10)测试是多余的/错误的
  6. 此外,即使使用固定#5,val仍然可以[合法地]为零(即)原始值 为零。因此,realloc循环必须重新架构,至少执行一次保证 valueArray NULL
  7. 好的,这可以处理崩溃,但程序仍然会产生不正确的结果,因为在行上方:

    val += j;
    

    我们需要乘以起始基数,如下所示:

    val *= startingBase;
    val += j;
    

    以下是带注释的版本。

    风格是:#if 0 /*original code*/ #else /*fixed code*/ #endif并且有评论解释事情[请原谅无偿风格的清理]:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>                      // library for isdigit
    #include <string.h>
    #include <curses.h>
    //#include "ylantron.h"                 // <-- my library
    
    #define MAX_SYMBOLS 36
    
    void pause();
    char *convert(char *value, int startingBase, int endingBase);
    char *swapArray(char *oldArray);
    
    // MAIN
    
    int
    main(int argc, char *argv[])
    {
    
        /* CHECK ARGUMENTS NUMBER */
        if (argc != 4) {
            printf("\n\e[91m[X]\e[39m Invalid number argument\n");
            pause();
            return 1;
        }
    
        /* CHECK ARGUMENTS */
        if ((isdigit(argv[1][0]) == 0) || (isdigit(argv[2][0]) == 0) || (isdigit(argv[3][0]) == 0)) {
            printf("\n\e[91m[X]\e[39m One of the arguments is not a number\n");
            pause();
            return 1;
        }
    
        /* CHECKING BASES */
        int check = 0;
        char *baseType = (char *) calloc(9, sizeof(char));
        char *infSup = (char *) calloc(10, sizeof(char));
        int numMinMax;
    
        int base_from;
        int base_to;
        char *val;
    
        base_from = atoi(argv[1]);
        val = argv[2];
        base_to = atoi(argv[3]);
    
        if (base_from < 2) {
            strcpy(baseType, "starting");
            strcpy(infSup, "inferior");
            numMinMax = 2;
            check = 1;
        }
        else if (base_from > MAX_SYMBOLS) {
            strcpy(baseType, "starting");
            strcpy(infSup, "superior");
            numMinMax = MAX_SYMBOLS;
            check = 1;
        }
        else if (base_to < 2) {
            strcpy(baseType, "ending");
            strcpy(infSup, "inferior");
            numMinMax = 2;
            check = 1;
        }
        else if (base_to > MAX_SYMBOLS) {
            strcpy(baseType, "ending");
            strcpy(infSup, "superior");
            numMinMax = MAX_SYMBOLS;
            check = 1;
        }
    
        if (check == 1) {
            printf("\n\e[91m[X]\e[39m The %s base can't be %s to %d\n",
                baseType, infSup, numMinMax);
    
            free(baseType);
            free(infSup);
    
            pause();
            return 1;
        }
    
        if (base_from == base_to) {
            printf("\n\e[93m[?]\e[39m Why you want me to convert a number with equal bases?");
            pause();
            return 1;
        }
    
        printf("\nThe result is %s\n\n", convert(val, base_from, base_to));
    
        return 0;
    }
    
    // FUNCTIONS
    
    void
    pause()
    {
    
        printf("\nPress any key...");
        getch();
        printf("\n");
    }
    
    char *
    convert(char *value, int startingBase, int endingBase)
    {
    
        char symbols[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
        char *valueArray = NULL;
        int val = 0;
    
        // NOTE/BUG: this should _always_ be executed regardless of base
    #if 0
        if (startingBase != 10) {
    #endif
            for (int i = 0; i < (strlen(value) / sizeof(char)); i++) {
                for (int j = 0; j < MAX_SYMBOLS; j++) {
                    if (value[i] == symbols[j]) {
                        // NOTE/BUG: when assembling the number we must multiply by
                        // the base
    #if 1
                        val *= startingBase;
    #endif
                        val += j;
                        break;
                    }
                }
            }
    #if 0
        }
    #endif
    
        // NOTE: for debug?
        printf("val: %d", val);
    
        // NOTE/BUGS:
        // (1) if val is zero, this loop will never be executed and
        //     valueArray will remain NULL
        // (2) if startingBase _is_ 10, then val could _never_ be non-zero
    #if 0
        for (int i = 1; val != 0;) {
            valueArray = (char *) realloc(valueArray, (++i) * sizeof(char));
            valueArray[i - 2] = symbols[(val % endingBase)];
            valueArray[i - 1] = '\0';
            val /= endingBase;
        }
    #else
        int i = 1;
        while (1) {
            valueArray = (char *) realloc(valueArray, (++i) * sizeof(char));
            valueArray[i - 2] = symbols[(val % endingBase)];
            valueArray[i - 1] = '\0';
            val /= endingBase;
            if (val == 0)
                break;
        }
    #endif
    
        // NOTE/BUG: this produces a segfault if valueArray is NULL
        swapArray(valueArray);
    
        return valueArray;
    }
    
    char *
    swapArray(char *oldArray)
    {
    
        char old;
        int i;
        int j;
    
        // NOTE/BUG: strlen gives segfault if oldArray is NULL
        for (i = 0, j = strlen(oldArray) - 1; i < (strlen(oldArray) / 2); i++, j--) {
            old = oldArray[i];
            oldArray[i] = oldArray[j];
            oldArray[j] = old;
        }
    
        return oldArray;
    }
    

    这是清理过的版本。

    除了删除&#34;丑陋&#34;旧代码和&#34;注意/ BUG&#34;评论,主要是,它改变了处理字符串的循环,从循环内部重复调用strlen来代替寻找EOS字符。我已经在几个循环中对此进行了更改,并生成了swapArray的一些变体以显示可以执行的操作。

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>                      // library for isdigit
    #include <string.h>
    #include <curses.h>
    //#include "ylantron.h"                 // <-- my library
    
    #define MAX_SYMBOLS 36
    
    void pause();
    char *convert(char *value, int startingBase, int endingBase);
    char *swapArray(char *oldArray);
    
    // MAIN
    
    int
    main(int argc, char *argv[])
    {
    
        /* CHECK ARGUMENTS NUMBER */
        if (argc != 4) {
            printf("\n\e[91m[X]\e[39m Invalid number argument\n");
            pause();
            return 1;
        }
    
        /* CHECK ARGUMENTS */
        if ((isdigit(argv[1][0]) == 0) || (isdigit(argv[2][0]) == 0) || (isdigit(argv[3][0]) == 0)) {
            printf("\n\e[91m[X]\e[39m One of the arguments is not a number\n");
            pause();
            return 1;
        }
    
        /* CHECKING BASES */
        int check = 0;
        char *baseType = (char *) calloc(9, sizeof(char));
        char *infSup = (char *) calloc(10, sizeof(char));
        int numMinMax;
    
        int base_from;
        int base_to;
        char *val;
    
        base_from = atoi(argv[1]);
        val = argv[2];
        base_to = atoi(argv[3]);
    
        if (base_from < 2) {
            strcpy(baseType, "starting");
            strcpy(infSup, "inferior");
            numMinMax = 2;
            check = 1;
        }
        else if (base_from > MAX_SYMBOLS) {
            strcpy(baseType, "starting");
            strcpy(infSup, "superior");
            numMinMax = MAX_SYMBOLS;
            check = 1;
        }
        else if (base_to < 2) {
            strcpy(baseType, "ending");
            strcpy(infSup, "inferior");
            numMinMax = 2;
            check = 1;
        }
        else if (base_to > MAX_SYMBOLS) {
            strcpy(baseType, "ending");
            strcpy(infSup, "superior");
            numMinMax = MAX_SYMBOLS;
            check = 1;
        }
    
        if (check == 1) {
            printf("\n\e[91m[X]\e[39m The %s base can't be %s to %d\n",
                baseType, infSup, numMinMax);
    
            free(baseType);
            free(infSup);
    
            pause();
            return 1;
        }
    
        if (base_from == base_to) {
            printf("\n\e[93m[?]\e[39m Why you want me to convert a number with equal bases?");
            pause();
            return 1;
        }
    
        printf("\nThe result is %s\n\n", convert(val, base_from, base_to));
    
        return 0;
    }
    
    // FUNCTIONS
    
    void
    pause()
    {
    
        printf("\nPress any key...");
        getch();
        printf("\n");
    }
    
    char *
    convert(char *value, int startingBase, int endingBase)
    {
        char symbols[] = { "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" };
        char *valueArray = NULL;
        int val = 0;
    
        for (int chr = *value++;  chr != 0;  chr = *value++) {
            for (int j = 0; j < MAX_SYMBOLS; j++) {
                if (chr == symbols[j]) {
                    val *= startingBase;
                    val += j;
                    break;
                }
            }
        }
    
        int i = 1;
        while (1) {
            valueArray = (char *) realloc(valueArray, (++i) * sizeof(char));
            valueArray[i - 2] = symbols[(val % endingBase)];
            valueArray[i - 1] = '\0';
            val /= endingBase;
            if (val == 0)
                break;
        }
    
        swapArray(valueArray);
    
        return valueArray;
    }
    
    char *
    swapArray(char *oldArray)
    {
        char old;
        int i;
        int j;
    
        for (i = 0, j = strlen(oldArray) - 1; i < (strlen(oldArray) / 2); i++, j--) {
            old = oldArray[i];
            oldArray[i] = oldArray[j];
            oldArray[j] = old;
        }
    
        return oldArray;
    }
    
    char *
    swapArray_2(char *oldArray)
    {
        char old;
        int len;
        int i;
        int j;
    
        len = strlen(oldArray);
        for (i = 0, j = len - 1; i < (len / 2); i++, j--) {
            old = oldArray[i];
            oldArray[i] = oldArray[j];
            oldArray[j] = old;
        }
    
        return oldArray;
    }
    
    char *
    swapArray_3(char *oldArray)
    {
        char *lhs;
        char *rhs;
        char old;
    
        lhs = oldArray;
        rhs = &lhs[strlen(lhs) - 1];
    
        for (;  lhs < rhs;  ++lhs, --rhs) {
            old = *lhs;
            *lhs = *rhs;
            *rhs = old;
        }
    
        return oldArray;
    }