user3810155
user3810155

Reputation:

c: difference in debug and release mode?

I'm trying to build a simple library for integer operations without bound (I know the existence of GMP, just for my self interest). I'm doing this by teaching the computer to do primary school arithmetics with char arrays. I know it is a very inefficient way, but that is what I can think of and am up to. I have succeeded to write a C code for all four +-*/ operations, but somehow only in debug mode. The code works perfectly fine both in the GDB and Visual Studio 2013 debug mode; I have tested more than enough. However, it keeps spitting out error during normal execution in release mode. I have searched a lot on this topic of having problems in release mode not detected during debug, but the solutions I found doesn't seem to fit to my case, at least within what I can see.

edit: what I mean by 'error' is that my code will execute 'goto error;', which means the calculation result was a mess, so it didn't pass my random integer calculation test given in main(). Such error happens not always but after about 10~20 successful operations during release mode. No single (any general) error occurs during debug.

Is it a very simple mistake I made in the code, a short fix of which will make everything so well? perhaps my whole code is just a crappy mess? is it some problem in my Windows 7 system? or anything else possible? I have done everything I can do myself to deal with this problem, but now I am merely clueless. Any kind help would be grateful.

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

#define A_PLUS -1
#define A_MINUS -2
#define INT_LEN 10

typedef struct{
    int sign;
    int start;
    char *num;
} abn;

void initABN(abn *n);
void sInitABN(abn *n, char *cs);
void iInitABN(abn *n, int num);
void sReInitABN(abn *n, char *cs);
void iReInitABN(abn *n, int num);
void delABN(abn *n);
int aBigger(const abn *king, const abn *slave);
void aPlus(abn *t, const abn *a, const abn *b);
void aMinus(abn *t, const abn *a, const abn *b);
void printABN(const abn *a);
int abnToInt(const abn *a);
int iPow(int base, int exp);

int fromElse = 0;

int main(){
    srand((unsigned)time(NULL));
    printf("number of tests for each operation: ");
    int testN;
    scanf("%d", &testN);
    printf("\n");
    abn a, b;
    initABN(&a); initABN(&b);
    int i, t1, t2;
    for (i = 0; i < testN; ++i){
        t1 = rand()*(2*(rand() % 2) - 1);
        t2 = rand()*(2*(rand() % 2) - 1);
        iReInitABN(&a, t1);
        iReInitABN(&b, t2);
        printABN(&a);
        printf(" + ");
        printABN(&b);
        printf(" = ");
        aPlus(&a, &a, &b);
        printABN(&a);
        if (t1 + t2 == abnToInt(&a)){
            printf(" TRUE\n");
        }else{
            goto error;
        }
    }
    for (i = 0; i < testN; ++i){
        t1 = rand()*(2*(rand() % 2) - 1);
        t2 = rand()*(2*(rand() % 2) - 1);
        iReInitABN(&a, t1);
        iReInitABN(&b, t2);
        printABN(&a);
        printf(" - ");
        printABN(&b);
        printf(" = ");
        aMinus(&a, &a, &b);
        printABN(&a);
        if (t1 - t2 == abnToInt(&a)){
            printf(" TRUE\n");
        }else{
            goto error;
        }
    }
    delABN(&a); delABN(&b);
    printf("Test Complete!\n");
    return 0;
    error:
    printf("\nERROR\n");
    system("pause");
    return 1;
}

void initABN(abn *n){
    n->num = NULL;
}

void sInitABN(abn *n, char *cs){
    int i;
    for (i = 0; cs[i] != 0; ++i); --i;
    if (cs[0] == '-'){
        n->sign = A_MINUS;
        n->start = i - 1;
        n->num = (char*)malloc(i);
        for (; i > 0; --i){
            n->num[n->start - i + 1] = cs[i] - '0';
        }
    }else{
        n->sign = A_PLUS;
        n->start = i;
        n->num = (char*)malloc(i + 1);
        for (; i >= 0; --i){
            n->num[n->start - i] = cs[i] - '0';
        }
    }
}

void iInitABN(abn *n, int num){
    char *tempCs = (char*)malloc(INT_LEN + 1);
    sprintf(tempCs, "%d", num);
    sInitABN(n, tempCs);
    free(tempCs);
}

void sReInitABN(abn *n, char *cs){
    free(n->num);
    sInitABN(n, cs);
}

void iReInitABN(abn *n, int num){
    char *tempCs = (char*)malloc(INT_LEN + 1);
    sprintf(tempCs, "%d", num);
    sReInitABN(n, tempCs);
    free(tempCs);
}

void delABN(abn *n){
    free(n->num);
    n->num = NULL;
}

int aBigger(const abn *king, const abn *slave){
    int kingSize = king->start, slaveSize = slave->start;
    if (kingSize > slaveSize){
        return 1;
    }
    if (kingSize < slaveSize){
        return 0;
    }
    int i;
    for (i = kingSize; i >= 0; --i){
        if (king->num[i] > slave->num[i]){
            return 1;
        }
        if (king->num[i] < slave->num[i]){
            return 0;
        }
    }
    return 0;
}

void aPlus(abn *t, const abn *a, const abn *b){
    int aSign = a->sign, bSign = b->sign;
    if (!fromElse){
        if (aSign != bSign){
            fromElse = 1;
            aMinus(t, a, b);
            fromElse = 0;
            return;
        }
    }
    char *temp;
    int aStart = a->start, bStart = b->start;
    if (aStart > bStart){
        t->start = aStart + 1;
        temp = (char*)calloc(aStart + 2, 1);
    }else{
        t->start = bStart + 1;
        temp = (char*)calloc(bStart + 2, 1);
    }
    int i, j;
    for (i = 0; i <= aStart; ++i){
        temp[i] += a->num[i];
    }
    for (i = 0; i <= bStart; ++i){
        temp[i] += b->num[i];
        if (temp[i] >= 10){
            temp[i] -= 10;
            ++temp[i + 1];
            for (j = i + 1; ; ++j){
                if (temp[j] >= 10){
                    temp[j] -= 10;
                    ++temp[j + 1];
                }else{
                    break;
                }
            }
        }
    }
    if (temp[t->start] == 0){
        --t->start;
    }
    if (aSign == A_PLUS){
        t->sign = A_PLUS;
    }else{
        t->sign = A_MINUS;
    }
    free(t->num);
    t->num = temp;
}

void aMinus(abn *t, const abn *a, const abn *b){
    int aSign = a->sign, bSign = b->sign;
    if (!fromElse){
        if (aSign != bSign){
            fromElse = 1;
            aPlus(t, a, b);
            fromElse = 0;
            return;
        }
    }
    char *temp;
    int aStart = a->start, bStart = b->start;
    if (aStart > bStart){
        t->start = aStart;
        temp = (char*)calloc(aStart + 1, 1);
    }else{
        t->start = bStart;
        temp = (char*)calloc(bStart + 1, 1);
    }
    int i;
    #define MIN_CALC(A, B)\
        for (i = 0; i <= A##Start; ++i){\
            temp[i] += A->num[i];\
        }\
        for (i = 0; i <= B##Start; ++i){\
            temp[i] -= B->num[i];\
            if (temp[i] < 0){\
                temp[i] += 10;\
                temp[i + 1] -= 1;\
            }\
        }
    if (aBigger(a, b)){
        MIN_CALC(a, b);
        if (aSign == A_PLUS){
            t->sign = A_PLUS;
        }else{
            t->sign = A_MINUS;
        }
    }else{
        MIN_CALC(b, a);
        if (aSign == A_PLUS){
            t->sign = A_MINUS;
        }else{
            t->sign = A_PLUS;
        }
    }
    for (i = t->start; i > 0; --i){
        if (temp[i] == 0){
            --t->start;
        }else{
            break;
        }
    }
    free(t->num);
    t->num = temp;
}

void printABN(const abn *a){
    if (a->start == 0 && a->num[0] == 0){
        printf("0");
        return;
    }
    if (a->sign == A_MINUS){
        printf("-");
    }
    int i;
    for (i = a->start; i >= 0; --i){
        printf("%d", a->num[i]);
    }
}

int abnToInt(const abn *a){
    int i, n = 0;
    for (i = 0; i <= a->start; ++i){
        n += a->num[i]*iPow(10, i);
    }
    if (a->sign == A_MINUS){
        n *= -1;
    }
    return n;
}

int iPow(int base, int exp){
    int n = 1;
    int i;
    for (i = 0; i < exp; ++i){
        n *= base;
    }
    return n;
}

Upvotes: 1

Views: 939

Answers (1)

The Dark
The Dark

Reputation: 8514

This is caused by the fact that t and a point to the same value. When you modify a value pointed to by t it will also modify the value pointed to by a.

In your aMinus function, you use the value of a->start indirectly in the call to aBigger. However, you have already changed the value of t->start and hence a->start earlier in the function.

Here are three ways of fixing the problem:

  1. Changing the code so that the modification to t->start happens later in the function (saving the value to a new local variable and setting just before it is needed) fixes that problem. This is the best way, I think.

  2. Changing the aBigger function to take the lengths as parameters and using aStart and bstart as the values works, but still means you have changed a->start and might forget and change the code to use a->start in the future.

  3. Change the call to put the result of the addition or subtraction into a different variable. This works, but it still means your function has a potential vulnerability.

I can't explain why it works in debug mode or when debugging release mode, I'll try stepping through and seeing if I can trace it further.

Upvotes: 1

Related Questions