Why is this free statement causing a heap corruption error?

时间:2016-02-03 03:44:33

标签: c arrays

I wrote some code but am not sure how to properly free memory dynamically allocated inside of a function.

What is the proper way to free memory without causing a heap corruption, or better yet, what is causing the corruption when trying to free `returnedAry``

  #include <stdio.h>
#include <stdlib.h>
#define MAX_NUM_DIGITS 10

void displayMainMenu(void);
int* extractUncommonDigit(int*, int);

int main() {
    displayMainMenu();

    return 0;
}

void displayMainMenu() {
    int* userAry = NULL;
    int* returnedAry = NULL;
    int menuOption;
    int numOfInts;
    int i;

    do {
        printf("\n\n*********************************************\n"
            "*                     MENU                  *\n"
            "* 1. Calling extractUncommonDigit()         *\n"
            "* 2. Quit                                   *\n"
            "*********************************************\n"
            "Select an option (1 or 2): ");
        scanf_s("%d", &menuOption);

        switch (menuOption) {
        case 1:
            printf("\n  How many integers? ");
            scanf_s("%d", &numOfInts);
            userAry = (int*)malloc(numOfInts * sizeof(int));

            for (i = 0; i < numOfInts; i++) {
                printf("    Enter integer #%d: ", i + 1);
                scanf_s("%d", &userAry[i]);
            }

            printf("\n  The original array: \n");
            for (i = 0; i < numOfInts; i++) {
                printf("    %d\n", userAry[i]);
            }

            printf("\n  Calling extractUncommonDigit() -\n");
            returnedAry = extractUncommonDigit(userAry, numOfInts);
            printf("\n  Displaying after returning the array"
                " -- The uncommon digits: ");

            if (returnedAry[0] != 0) {
                printf("\n    There is/are %d uncommon digit(s)", returnedAry[0]);
                for (int i = 1; i < returnedAry[0] + 1; i++) {
                    printf("\n      %d", *(returnedAry + i));
                }
            } else {
                printf("\n   There is/are no uncommon digit(s)");
            }
            break;
        case 2:
            free(userAry);
            /* This line causes heap corruption error
            -----------------------------------------
            free(returnedAry);
            -----------------------------------------
            */
            printf("\n  Fun Excercise ...");
            break;
        default:
            printf("\n  WRONG OPTION!");
            break;
        }
    } while (menuOption != 2);

    free(userAry);

    return;
}

int* extractUncommonDigit(int* ary, int size) {
    int* assembledAry = 0;
    int tmp;
    int** digitInfoAry = (int**)malloc(size * sizeof(int*));
    int i, j;
    int digitAry[10] = { 0 };
    int uncommonCount = 0;

    for (i = 0; i < size; i++) {
        *(digitInfoAry + i) = (int*)calloc(MAX_NUM_DIGITS, sizeof(int));
    }

    for (i = 0; i < size; i++) {
        tmp = *(ary + i) < 0 ? -(*(ary + i)) : *(ary + i);

        do {
            *(*(digitInfoAry + i) + tmp % 10) = 1;
            tmp /= 10;
        } while (tmp != 0);
    }

    for (i = 0; i < MAX_NUM_DIGITS; i++) {
        for (j = 0; j < size; j++) {
            digitAry[i] += *(*(digitInfoAry + j) + i);
        }
    }

    for (i = 0; i < MAX_NUM_DIGITS; i++) {
        if (digitAry[i] == 1) {
            uncommonCount++;
        }
    }

    assembledAry = (int*)malloc(uncommonCount * sizeof(int) + 1);
    *assembledAry = uncommonCount;

    if (uncommonCount != 0) {
        for (i = 0, j = 1; i < MAX_NUM_DIGITS; i+=2) {
            if (digitAry[i] == 1) {
                assembledAry[j] = i;
                j++;
            }
        }
        for (i = 1; i < MAX_NUM_DIGITS; i+=2) {
            if (digitAry[i] == 1) {
                assembledAry[j] = i;
                j++;
            }
        }
    }

    free(digitInfoAry);

    return assembledAry;
}

The commented text displays where the program crashes after running the debugger. What am i doing wrong?

2 个答案:

答案 0 :(得分:0)

I expect the problem is here, where you don't allocate enough memory and then later write off the end of the block, invoking undefined behaviour:

assembledAry = (int*)malloc(uncommonCount * sizeof(int) + 1);

You actually want (uncommonCount + 1) * sizeof(int) bytes.

Unrelated, but you also have a leak when freeing digitInfoAry (because you don't free all the allocated pointers it contains), and you are double-freeing userAry just before leaving main.

答案 1 :(得分:0)

If the user inputs a '1' more than once, memory leaks occur

If the user inputs a '2' after previously entering '1', one ERROR occurs

If the user inputs a '2' without having previously entered '1', two ERRORS occur

do {
    switch (menuOption) {
    case 1:
        userAry = (int*)malloc(...);    //may not get executed
        returnedAry = extractUncommonDigit(...); //may not get executed
        break;
    case 2:
        free(userAry);    //can produce ERROR
        free(returnedAry);//can produce ERROR
        break;
    default:
        break;
    }
} while (menuOption != 2);
free(userAry);            //ERROR, tried to free 'userAry' twice

and the function called:

int* extractUncommonDigit(...) {...}
相关问题