【问题标题】:C: adding element to dynamically allocated arrayC:将元素添加到动态分配的数组
【发布时间】:2014-06-19 10:45:53
【问题描述】:

我尝试通过 Google 搜索解决方案:我找不到任何有用的东西;甚至似乎我做得对。我能找到的唯一一页是关于通过一个函数发送我的动态分配的数组,该函数处理位于结构内的数组,这当然是标量,因此行为不同。我现在不想使用结构——我正在尝试了解 DAM 并使用指针和函数。

也就是说,我确信它非常初级,但我被卡住了。代码可以编译,但是当我运行可执行文件时它会冻结。 (如果这很重要,我正在使用 minGW gcc。而且我现在还不清楚如何使用 gdb。)

下面是代码(最后,我希望整个代码是一个类似 ArrayList 的数据结构):

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

void add( int element, int *vector);
void display_vector( int *vector );
void initialize_vector( int *vector );

int elements = 0;
int size = 10;

int main(void)
{
    int *vector = 0; 
    initialize_vector(vector);
    add(1, vector);
    //add(2, vector);
    //add(3, vector);
    //add(4, vector);
    //add(5, vector);
    //add(6, vector);
    //add(7, vector);
    //add(8, vector);
    //add(9, vector);
    //add(10, vector);
    //add(11, vector);
    display_vector(vector); 

    return 0;
}

void add( int element, int *vector)
{
    vector[elements++] = element;
    return;
}

void display_vector( int *vector )
{
    int i;
    for( i = 0; i < elements; i++)
    {
        printf("%2d\t", vector[i]);
        if( (i + 1) % 5 == 0 )
            printf("\n");
    }
    printf("\n");
    return; 
}

void initialize_vector( int *vector )
{
    vector = (int *)malloc(sizeof(int) * size);

}

【问题讨论】:

  • 为什么elementssize是全局变量,而vector是局部变量?由于全局 elements 变量的存在,您不能拥有多个向量,因此您不妨将 vector 也设为全局变量。
  • 您正在将新分配的内存的地址分配给本地指针。原始指针仍然是 NULLPTR。
  • 非常好的点@Barmar。
  • @alvits,那我不应该让原始指针为空吗?它按照现在设置的方式运行,更改了 dboals 代码。

标签: c arrays pointers dynamic-memory-allocation


【解决方案1】:

除了的其他回复,我会建议另一种方法。

假设至少符合C99 的编译器,我宁愿建议将分配的大小保留在以flexible array member 结尾的结构的成员中(另请参阅this),例如:

 typedef struct vector_st {
    unsigned count; // used length
    unsigned size;  // allocated size, always >= length
    int vectarr[];
 } Vector;

然后你会构造这样一个向量

 Vector* make_vector (unsigned size) { 
   Vector* v = malloc(sizeof(Vector)+size*sizeof(int));
   if (!v) { perror("malloc vector"); exit (EXIT_FAILURE); };
   memset (v->vectarr, 0, size*sizeof(int));
   v->count = 0;
   v->size = size;
 }

将元素添加到向量中,返回原始向量或增长的向量:

Vector* append_vector (Vector*vec, int elem) {
  assert (vec != NULL);
  unsigned oldcount = vec->count;
  if (oldcount < vec->size) {
     vec->vectarr[vec->count++] = elem;
     return vec;
  } else {
     unsigned newsize = ((4*oldcount/3)|7) + 1;
     Vector* oldvec = vec;
     vec = malloc(sizeof(Vector)+newsize*sizeof(int));
     if (!vec) { perror("vector grow"); exit(EXIT_FAILURE); };
     memcpy (vec->vectarr, oldvec->vectarr, oldcount*sizeof(int));
     memset (vec->vectarr + oldcount, 0, 
             (newsize-oldcount) * sizeof(int));
     vec->vectarr[oldcount] = elem;
     vec->count = oldcount+1;
     vec->size = newsize;
     free (oldvec);
     return vec;
  }
}

你可以编码:

Vector* myvec = make_vector(100);
myvec = append_vector(myvec, 35);
myvec = append_vector(myvec, 17);
for (int i=0; i<150; i++)
   myvec = append_vector(myvec, i*2);

要释放这样的向量,只需使用free(myvec);


如果您真的不想使用任何struct,您应该在单独的变量中保留向量的使用长度、向量的分配大小、指向动态分配数组的指针:

  unsigned used_count; // useful "length"
  unsigned allocated_size; // allocated size, always not less than used_count
  int *dynamic_array; // the pointer to the dynamically allocated array

如果您希望能够管理多个向量,则可以将上述有用的长度、分配的大小和动态数组打包到一些 struct dynamic_array_st 中(您可以将其指针传递给适当的例程,例如 make_dynamic_vector(struct dynamic_array_st*)append_dynamic_vector(struct dynamic_array_st*, int) , etc ....) 或者将它们作为三个单独的形式传递给类似的例程,然后你需要传递它们的 address 因为例程会改变它们,例如create_dynamic_vector(unsigned *countptr, unsigned *sizeptr, int**vectarrptr) 您可以调用为 create_dynamic_vector(&amp;mycount, &amp;mysize, &amp;myvectarr); 等。

我确实认为灵活的数组成员仍然是最干净的方法。

【讨论】:

    【解决方案2】:

    进行了编辑以使其更加清晰。

    问题是您的 init 例程正在使用“向量”的副本,并且正在分配到该副本而不是原始向量指针。从初始化返回时,您会丢失指向内存块的指针。

    在此函数中将向量的参数更改为句柄(指向指针的指针)

    void initialize_vector( int **vector )
    {
        *vector = (int *)malloc(sizeof(int) * size);
    }
    

    然后把对init的调用改成这个

    initialize_vector(&vector);
    

    我没有编译这个,但它应该修复代码。

    【讨论】:

    • 应该是*vector = ...
    【解决方案3】:

    在 C 中,函数参数是按值传递的,这意味着您传递给函数的每个参数都有一个本地副本,如果您更改函数中的参数,您只会更改该参数的本地副本。因此,如果要更改函数中参数的值,则需要将其地址传递给该函数,取消引用该地址并分配给该函数中的结果。

    理论说得够多了,下面是修复代码的方法:

    void initialize_vector( int **vector );
    
    initialize_vector(&vector);
    
    void initialize_vector( int **vector )
    {
        *vector = (int *)malloc(sizeof(int) * size);
    
    }
    

    【讨论】:

    • 非常感谢@Lee Duhem。我为你 +1 了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 2013-08-04
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    相关资源
    最近更新 更多