c - 指针和动态内存

标签 c pointers memory-management malloc

我有一个返回数组指针的函数。我正在循环中运行它,并且 free() 似乎给我带来了问题。我不确定在哪里,但似乎在主循环中的某个地方正在使用我试图释放的内存。我在 10.6 中使用 Xcode 3.2.1 |调试| x86_64 版本。

程序将运行一次主循环;第二次遇到 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)

一起享受乐趣

关于c - 指针和动态内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4351399/

相关文章:

r - 用相同的对象有效地填充列表

linux - 在Linux单板计算机上安装USB以在C程序中使用

c - 初学者 ftp 服务器困境,部分 deux

c - 为什么这个链表会出现段错误?

java - 从被调用方法中获取局部变量的值而不返回

python - 计算范围 (0,n] 中数字 'x' 的出现次数

python - 是否有其他方法可以将预先训练的词嵌入完全加载到内存中?

c - 为什么在免费声明中没有提供尺寸

c - 了解 C 中的地址

c++ - 通过引用传递整数到 C++ 中的类