简体   繁体   中英

Pointers and Dynamic Memory

I have a function that returns a pointer to an array. I'm running it in a loop and free() seems to be giving me problems. I'm not sure where, but it appears that somewhere in the main loop the memory that I'm trying to free is being used. I'm using Xcode 3.2.1 in 10.6 | Debug | x86_64 build.

The program will run through the main loop one time; the second time it encounters the free() it gives me the following error:

malloc: *** error for object 0x100100180: incorrect checksum for freed object -
object was probably modified after being freed.

Can someone point out (no pun intended) what I'm doing wrong with pointers here?

Here is the program:

int main(int argc, char **argv) {
    int *partition;
    int lowerLimit;
    int upperLimit;

    // snip ... got lowerLimit and upperLimit from console arguments

    // this is the 'main loop':
    for (int i = lowerLimit; i <= upperLimit; i += 2) {
        partition = goldbachPartition(i);
        printOutput(partition[0], partition[1], i);
        free(partition); // I get problems on the second iteration here
    }

    return 0;
}


int *goldbachPartition(int x) {
    int solved = 0;
    int y, z;
    int *primes;
    int *result;

    result = intAlloc(2);

    primes = atkinsPrimes(x);

    for (int i = intCount(primes)-1; i >= 0; i--) {
        y = primes[i];
        for (int j = 0; j < y; j++) {
            z = primes[j];
            if (z + y >= x) {
                break;
            }
        }
        if (z + y == x) {
            solved = 1;
            result[0] = y;
            result[1] = z;
            break;
        } else if (y == z) {
            result[0] = 0;
            result[1] = 0;
            break;
        }
    }
    free(primes);

    return result;
}


int *atkinsPrimes(int limit) {
    int *primes;
    int *initialPrimes;
    int *filtered;
    int *results;
    int counter = 0;
    int sqrtLimit;
    int xLimit;
    int resultsSize;

    primes = intAlloc(limit+1);
    intFillArray(primes, limit+1, 0);

    sqrtLimit = floor(sqrt(limit));
    xLimit = floor(sqrt((limit+1) / 2));

    // these loops are part of the Atkins Sieve implementation
    for (int x = 1; x < xLimit; x++) {
        int xx = x*x;
        for (int y = 1; y < sqrtLimit; y++) {
            int yy = y*y;
            int n = 3*xx + yy;
            if (n <= limit && n % 12 == 7) {
                primes[n] = (primes[n] == 1) ? 0 : 1;
            }
            n += xx;
            if (n <= limit && (n % 12 == 1 || n % 12 == 5)) {
                primes[n] = (primes[n] == 1) ? 0 : 1;
            }
            if (x > y) {
                n -= xx + 2*yy;
                if (n <= limit && n % 12 == 11) {
                    primes[n] = (primes[n] == 1) ? 0 : 1;
                }
            }
        }
    }

    for (int n = 5; n < limit; n++) {
        if (primes[n] == 1) {
            for (int k = n*n; k < limit; k += n*n) {
                primes[k] = 0;
            }
        }
    }

    initialPrimes = intAlloc(2);

    if (limit >= 2) {
        initialPrimes[counter++] = 2;
    }
    if (limit >= 3) {
        initialPrimes[counter++] = 3;
    }

    filtered = intFilterArrayKeys(primes, limit+1);
    results = intMergeArrays(initialPrimes, filtered, counter, trueCount(primes, limit+1));
    resultsSize = counter + trueCount(primes, limit+1);

    free(primes);
    free(initialPrimes);
    free(filtered);

    results[resultsSize] = 0;

    return results;
}

int trueCount(int *subject, int arraySize) {
    int count = 0;

    for (int i = 0; i < arraySize; i++) {
        if (subject[i] == 1) {
            count++;
        }
    }
    return count;
}


int intCount(int *subject) {
    // warning: expects 0 terminated array.
    int count = 0;

    while (*subject++ != 0) {
        count++;
    }

    return count;
}


void intFillArray(int *subject, int arraySize, int value) {
    for (int i = 0; i < arraySize; i++) {
        subject[i] = value;
    }
}


int *intFilterArrayKeys(int *subject, int arraySize) {
    int *filtered;
    int count = 0;

    filtered = intAlloc(trueCount(subject, arraySize));
    for (int i = 0; i < arraySize; i++) {
        if (subject[i] == 1) {
            filtered[count++] = i;
        }
    }

    return filtered;
}


int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2) {
    int *merge;
    int count = 0;

    merge = intAlloc(arraySize1 + arraySize2);

    for (int i = 0; i < arraySize1; i++) {
        merge[count++] = subject1[i];
    }
    for (int i = 0; i < arraySize2; i++) {
        merge[count++] = subject2[i];
    }

    return merge;
}

int *intAlloc(int amount) {
    int *ptr;
    ptr = (int *)malloc(amount * sizeof(int));
    if (ptr == NULL) {
        printf("Error: NULL pointer\n");
    }
    return ptr;
}

void printOutput(int num1, int num2, int rep) {
    if (num1 == 0) {
        printf("%d: No solution\n", rep);
        exit(0);
    } else {
        printf("%d = %d + %d\n", rep, num1, num2);
    }
}

Why is intAlloc not returning int* ?

int *intAlloc(int amount) {
    int *ptr;

    ptr = (int *)malloc(amount * sizeof(int));
    if(ptr == NULL) {
        printf("Error: NULL pointer\n");
        exit(1);
    }
    return ptr; //like this
}

EDIT (after your update):

On atkinsPrimes() where is filtered being intAlloc()ed ?

int *atkinsPrimes(int limit) {
    int *primes;
    int *initialPrimes;
    int *filtered;
    int *results;
    int resultsSize;

    primes = intAlloc(limit+1);

    // ...

    initialPrimes = intAlloc(2);

    // ...

    resultsSize = counter + trueCount(primes, limit+1);

    free(primes);
    free(initialPrimes);
    free(filtered); // Where was it intAlloc()ed?

    results[resultsSize] = 0; // make the array 0-terminated to make it easier to work with

    return results;
}

EDIT (after your N-th update):

This is a compilable version of your code. It ran smooth on my machine, no crashes. Compiled with g++ (due to declarations of variables inside the for statement):

g++ (Debian 4.3.2-1.1) 4.3.2

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

int *goldbachPartition(int x);
int *atkinsPrimes(int limit);
int trueCount(int *subject, int arraySize);
int intCount(int *subject) ;
void intFillArray(int *subject, int arraySize, int value);
int *intFilterArrayKeys(int *subject, int arraySize);
int *intAlloc(int amount);
void printOutput(int num1, int num2, int rep) ;
int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2);


int main(int argc, char **argv) {
    if (argc < 3) {
        printf("Usage: ./program <lower> <upper>\n");
        return 0;
    }


    int *partition;
    int lowerLimit = atoi(argv[1]);
    int upperLimit = atoi(argv[2]);

    // snip ... got lowerLimit and upperLimit from console arguments

    // this is the 'main loop':
    for (int i = lowerLimit; i <= upperLimit; i += 2) {
        partition = goldbachPartition(i);
        printOutput(partition[0], partition[1], i);
        free(partition); // I get problems on the second iteration here
    }

    return 0;
}


int *goldbachPartition(int x) {
    int solved = 0;
    int y, z;
    int *primes;
    int *result;

    result = intAlloc(2);

    primes = atkinsPrimes(x);

    for (int i = intCount(primes)-1; i >= 0; i--) {
        y = primes[i];
        for (int j = 0; j < y; j++) {
            z = primes[j];
            if (z + y >= x) {
                break;
            }
        }
        if (z + y == x) {
            solved = 1;
            result[0] = y;
            result[1] = z;
            break;
        } else if (y == z) {
            result[0] = 0;
            result[1] = 0;
            break;
        }
    }
    free(primes);

    return result;
}


int *atkinsPrimes(int limit) {
    int *primes;
    int *initialPrimes;
    int *filtered;
    int *results;
    int counter = 0;
    int sqrtLimit;
    int xLimit;
    int resultsSize;

    primes = intAlloc(limit+1);
    intFillArray(primes, limit+1, 0);

    sqrtLimit = floor(sqrt(limit));
    xLimit = floor(sqrt((limit+1) / 2));

    for (int x = 1; x < xLimit; x++) {
        int xx = x*x;
        for (int y = 1; y < sqrtLimit; y++) {
            int yy = y*y;
            int n = 3*xx + yy;
            if (n <= limit && n % 12 == 7) {
                primes[n] = (primes[n] == 1) ? 0 : 1;
            }
            n += xx;
            if (n <= limit && (n % 12 == 1 || n % 12 == 5)) {
                primes[n] = (primes[n] == 1) ? 0 : 1;
            }
            if (x > y) {
                n -= xx + 2*yy;
                if (n <= limit && n % 12 == 11) {
                    primes[n] = (primes[n] == 1) ? 0 : 1;
                }
            }
        }
    }

    for (int n = 5; n < limit; n++) {
        if (primes[n] == 1) {
            for (int k = n*n; k < limit; k += n*n) {
                primes[k] = 0;
            }
        }
    }

    initialPrimes = intAlloc(2);

    if (limit >= 2) {
        initialPrimes[counter++] = 2;
    }
    if (limit >= 3) {
        initialPrimes[counter++] = 3;
    }

    filtered = intFilterArrayKeys(primes, limit+1);
    results = intMergeArrays(initialPrimes, filtered, counter, trueCount(primes, limit+1));
    resultsSize = counter + trueCount(primes, limit+1);

    free(primes);
    free(initialPrimes);
    free(filtered);

    results[resultsSize] = 0;

    return results;
}

int trueCount(int *subject, int arraySize) {
    int count = 0;

    for (int i = 0; i < arraySize; i++) {
        if (subject[i] == 1) {
            count++;
        }
    }
    return count;
}


int intCount(int *subject) {
    // warning: expects 0 terminated array.
    int count = 0;

    while (*subject++ != 0) {
        count++;
    }

    return count;
}


void intFillArray(int *subject, int arraySize, int value) {
    for (int i = 0; i < arraySize; i++) {
        subject[i] = value;
    }
}


int *intFilterArrayKeys(int *subject, int arraySize) {
    int *filtered;
    int count = 0;

    filtered = intAlloc(trueCount(subject, arraySize));
    for (int i = 0; i < arraySize; i++) {
        if (subject[i] == 1) {
            filtered[count++] = i;
        }
    }

    return filtered;
}


int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2) {
    int *merge;
    int count = 0;

    merge = intAlloc(arraySize1 + arraySize2);

    for (int i = 0; i < arraySize1; i++) {
        merge[count++] = subject1[i];
    }
    for (int i = 0; i < arraySize2; i++) {
        merge[count++] = subject2[i];
    }

    return merge;
}

int *intAlloc(int amount) {
    int *ptr;
    ptr = (int *)malloc(amount * sizeof(int));
    if (ptr == NULL) {
        printf("Error: NULL pointer\n");
    }
    return ptr;
}

void printOutput(int num1, int num2, int rep) {
    if (num1 == 0) {
        printf("%d: No solution\n", rep);
        exit(0);
    } else {
        printf("%d = %d + %d\n", rep, num1, num2);
    }
}

Since you are still omitting some source, I can only imagine that the problem is hidden there.

EDIT : (my last update)

To assist your debugging, you should replace your main() function by the one below:

int main(int argc, char **argv) 
{
    int *primes = NULL;

    primes = atkinsPrimes(44); // Evil magic number

    free(primes);

    return 0;
}

Having a minimal example to reproduce the behavior you pointed out is much better then the whole thing. Have fun with atkinsPrimes(44)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM