繁体   English   中英

指针和动态记忆

[英]Pointers and Dynamic Memory

我有一个函数,它返回一个指向数组的指针。 我正在循环中运行它而free()似乎给了我一些问题。 我不知道在哪里,但似乎在主循环的某个地方我正在尝试释放的内存被使用。 我在10.6中使用Xcode 3.2.1 | 调试| x86_64 build。

该程序将在主循环中运行一次; 第二次遇到free()时会出现以下错误:

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

有人可以指出(没有双关语)我在这里用指针做错了吗?

这是程序:

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);
    }
}

为什么intAlloc不返回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
}

编辑 (更新后):

atkinsPrimes()中过滤的是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;
}

编辑 (在第N次更新后):

这是您的代码的可编译版本。 它在我的机器上顺利运行,没有崩溃。 用g ++编译(由于for语句中的变量声明):

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);
    }
}

由于您仍在省略某些来源,因此我只能想象问题隐藏在那里。

编辑 :(我上次更新)

为了帮助您进行调试,您应该用以下方法替换main()函数:

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

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

    free(primes);

    return 0;
}

有一个最小的例子来重现你指出的行为比整个事情要好得多。 玩得开心atkinsPrimes(44)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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