C:数组没有正确分配更多内存

时间:2016-02-10 14:03:05

标签: c arrays

我是C的新手,我正在从事一个项目。给定一个整数数组,我想将其中的所有零移动到数组的左侧,其余元素按任意顺序移动到所有零的右侧。我的算法的基本思想是计算数组中的零个数,从旧数组中创建一个新数组,其中包含零个数,然后"追加"其余的非零整数到这个数组上。然后我当然打印成品。

int main(int argc, const char * argv[]) {
    int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
    int n = 10, count = 0;

    // counts the number of 0's in the original array
    for (int i = 0; i < n; ++i)
    {
        if (a[i] == 0)
        {
            ++count;
        }
    }

    // creates a new array and makes each element 0
    int *array = NULL;
    for (int j = 0; j < count; ++j)
    {
        array = realloc(array, (j + 1) * sizeof(int));
        array[j] = 0;
    }

    // adds the nonzero elements of the array to the new array
    for (int l = count; l < n; ++l)
    {
        array = realloc(array, l * sizeof(int)); // getting an error here
        if (a[l] != 0)
        {
            array[l+count] = a[l];
        }
    }

    // prints the array out in a nice format
    printf("%s", "{");
    for (int k = 0; k < n-1; ++k)
    {
        printf("%d%s", array[k], ",");
    }

    printf("%d", array[n-1]);
    printf("%s", "}\n");


    free(array);
    return 0;
}

我得到了一个&#34;线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x40)&#34;运行此代码时出错。我认为它必须对新阵列的无效指针做一些事情,但我不确定如何解决它。

6 个答案:

答案 0 :(得分:7)

src/

这将访问array[l+count] = a[l]; 指向超出其分配大小的内存块。您必须使用第二个索引以不同方式执行此操作:

array

答案 1 :(得分:1)

关于您的算法:

我认为你不需要创建一个新数组,只需使用int tmp作为交换区域,并使用int foundZeroCount作为索引,u一次交换2个数字。

关于内存分配:

如果你想为固定大小的数组分配内存,只需使用malloc()分配一次数组,稍后当你需要扩展数组时,只需调用realloc()一次。

关于内存重置:

只需使用memset(),不需要循环。

建议 - 关于c编程

尝试改进您的基本知识,尤其是关于array / pointer / memory,并尝试从glibc了解更多功能。

我想,<The c programming language 2nd>GNU c library document<The linux programming interface>这样的图书很有用。

答案 2 :(得分:1)

其他答案解决了您的直接问题,

            array[l+count] = a[l];

尝试访问array指向的已分配空间的边界之外。我会专注于你解决问题的方法,这是有缺陷的。

动态内存分配比较昂贵。你不想做任何必要的事情,而且每次重新分配多次以小增量增加的形式特别差,就像你一样。

由于您在编译时知道需要多少元素,因此这里完全没有动态分配。你可以这样做:

int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
int array[10] = { 0 };

(另请注意,当提供数组初始值设定项时,未显式初始化的任何数组元素都会初始化为0。)

即使你在编译时不知道你需要多少元素,在一个块中执行整个分配会好得多。此外,如果您通过calloc()执行此操作,那么您将自动将已分配的空间初始化为全零。

答案 3 :(得分:1)

当您完成分配零数组&#39;时,问题在于array[l+count] = a[l];。它的大小 3 ,然后您尝试访问(l + count) 6 的位置。

即使你已经用记忆修复了这些问题,它仍然无法正常工作,因为 a [l]并且可能仍然是零。(你的初始阵列不是吗?在开始时有零,还记得吗?)

还有一些建议: 使用calloc()来构建初始的零数组,因为 man 状态:

  

calloc()函数为nmemb元素数组分配内存   每个大小字节数,并返回指向已分配内存的指针。该   内存设置为零

首先分配然后设置因为具有内存的操作对性能非常重要。最好先分配一些内存并使用它而不是每一步重新分配它。跟踪它也会容易得多。

答案 4 :(得分:0)

在定义数组之前已知计数。您可以使用malloc分配内存,如下所示。

array = malloc( count * sizeof(int)).

该错误表示您正在尝试访问地址0x40。这表示其中一个指针变为NULL,并且您尝试取消引用ptr + 0x40。

答案 5 :(得分:0)

在你开始攻击之前,请花点时间考虑一下你所描述的实际问题:

  

计算数组中的零个数,从旧数组中创建一个新数组,其中包含零个数,然后将其余的非零整数“追加”到该数组上。

您的评论说明代码应该做什么,但代码完全不同。你解决问题的算法是错误的 - 这就是错误的原因。

首先,如果新数组应该包含旧数组的所有零加上所有非零,那么常识说新数组将始终具有与旧数组相同的大小。您甚至不需要使用动态内存分配。

您所拥有的代码会创建一个新阵列,并在同一个内存位置一遍又一遍地丢弃旧阵列。这没有任何意义。最重要的是,在循环中重复调用realloc是非常无效的。

你应该做这样的事情:

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

int main(int argc, const char * argv[]) {
    int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
    const int n = 10; 

    // counts the number of 0's in the original array
    int zeroes = 0;
    for (int i = 0; i < n; ++i)
    {
        if (a[i] == 0)
        {
            ++zeroes;
        }
    }

    // creates a new array and makes each element 0
    // there's actually no need to allocate this dynamically at all...
    int *array = calloc(1, sizeof(int[n]) ); 
    assert(array != NULL);

    // skip zeroes, ie "move the zeroes from the original array"
    int* not_zeroes = array + zeroes; // point at first item to contain "not zeroes"

    // adds the non-zero elements of the original array to the new array
    for (int i = 0; i < n; ++i)
    {
      if(a[i] != 0)
      {
        *not_zeroes = a[i]; 
        not_zeroes++;
      }
    }

    // prints the array out in a nice format
    printf("%s", "{");
    for (int i = 0; i < n; ++i)
    {
        printf("%d,", array[i]);
    }
    printf("}\n");


    free(array);
    return 0;
}