有没有办法仅使用malloc和free函数来更改数组大小?

时间:2019-05-12 14:18:27

标签: c malloc free memory-reallocation

作为家庭作业,我必须编写一个仅使用mallocfree函数来更改数组大小的函数。

我知道如何使用realloc,但是我不知道如何使用malloc

typedef struct{
    int *tab;
    int size;
}arr;

我需要编写此函数:

void changeSizeDyn(arr *Dyn_arr, int size){
    //
}

如作业中所述:它只需要一个重新分配和一个内存释放,以及旧数组中元素的一个副本。 我进行了很多搜索,但仅使用realloc找到了结果。

是否可以不使用realloc来做到这一点?

5 个答案:

答案 0 :(得分:5)

  1. 使用malloc分配新大小的内存。
  2. 将所有字节从旧内存复制到新内存。您可以循环执行此操作,实际上不需要为此使用函数(如果是分配的话)。
  3. 释放旧内存。

答案 1 :(得分:1)

此功能乍一看并不简单。

您在这里。

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

typedef struct
{
    int *tab;
    int size;
} arr;

int changeSizeDyn( arr *Dyn_arr, int size )
{
    int success = 1;

    if ( Dyn_arr->size != size )
    {
        int *tmp = NULL;

        if ( size != 0 )
        {
            tmp = malloc( size * sizeof( int ) );
            success = tmp != NULL;

            if ( success )
            {
                int n = 0;

                if ( Dyn_arr->size != 0 )
                {
                    n = size < Dyn_arr->size ? size : Dyn_arr->size;

                    memcpy( tmp, Dyn_arr->tab, n * sizeof( int ) );
                }

                if ( n < size ) memset( tmp + n, 0, ( size - n ) * sizeof( int ) );
            }
        }

        if ( success )
        {
            free( Dyn_arr->tab );

            Dyn_arr->tab = tmp;
            Dyn_arr->size = size;
        }
    }

    return success;
}

int main( void )
{
    arr a = { NULL, 0 };
    int size = 10;

    if ( changeSizeDyn( &a, size ) )
    {
        for ( int i = 0; i < size; i++ ) a.tab[i] = i;

        for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
        putchar( '\n' );
    }

    size = 5;

    if ( changeSizeDyn( &a, size ) )
    {
        for ( int i = 0; i < size; i++ ) a.tab[i] = i;

        for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
        putchar( '\n' );
    }

    size = 0;

    if ( changeSizeDyn( &a, size ) )
    {
        for ( int i = 0; i < size; i++ ) a.tab[i] = i;

        for ( int i = 0; i < size; i++ ) printf( "%d ", a.tab[i] );
        putchar( '\n' );
    }

    assert( a.tab == NULL && a.size == 0 );
}

程序输出为

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 

该函数具有返回类型int,以指示其调用是否成功。您需要一种方法来确定函数调用是否成功。否则将无法确定。因此,使用类型void作为函数的返回类型是一个坏主意。

默认情况下,该函数将与旧数组的元素不对应的所有新元素设置为零。实际上,这不是必需的,但是可以使结构的使用更加清晰。

如果用户传递的大小等于0,则该函数将释放旧数组并将数据成员tab设置为NULL

如果数组的新大小和旧大小相等,则该函数不执行任何操作。

请注意,最好将结构的数据成员size声明为类型size_t。否则,您需要在函数size中是否添加负号。我之所以没有这样做,是因为我想您确实会在结构(和函数)声明中使用类型size_t而不是类型int

答案 2 :(得分:1)

struct Arr {
        int *tab;
        ptrdiff_t nmemb;
};

假设您最初是这样分配数组的:

struct Arr x;

x.nmemb = 7;
x.tab = malloc(sizeof(*x.tab) * x.nmemb);

您应该使用以下函数重新分配它:

void change_size_dyn(struct Arr *dyn_arr, ptrdiff_t nmemb)
{
        struct Arr old;
        ptrdiff_t cp_nmemb;

        if (!dyn_arr)
                return;
        old = *dyn_arr;

        if (nmemb <= 0)
                goto err;
        dyn_arr->tab = malloc(sizeof(*dyn_arr->tab) * nmemb);
        dyn_arr->nmemb = nmemb;

        cp_sz = MIN(old.nmemb, nmemb);
        memcpy(dyn_arr->tab, old.tab, cp_nmemb);
        free(old.tab);

        return;
err:
        dyn_arr->tab = NULL;
        dyn_arr->nmemb = 0;
        free(old.tab);
}

应该这样称呼:

change_size_dyn(&x, 9);

即使是第一次分配,您也可以使用此功能(尽管您应该首先将NULL0都设置为两个值)。您也不需要添加免费;输入0即可为您完成,就像realloc一样:

int main(void)
{
        struct Arr x = {0};

        change_size_dyn(&x, 5);
        /* ... */
        change_size_dyn(&x, 9);
        /* ... */

cleanup:
        change_size_dyn(&x, 0);
        return 0;
}

如果您传递的结构中dyn_arr->nmemb已经是负值(不应发生),则行为是不确定的(该负值将进入memcpy,将其包装为一个非常大的值)。高size_t,这会使数组溢出)。我不想进行检查,因为在任何非越野车场景中都没有必要。

答案 3 :(得分:1)

  

是否甚至可以在不使用realloc的情况下做到这一点?

可以。

例如,您可以这样做:

#include <stdlib.h> /* for malloc () and free () and EXIT_xxx macros. */
#include <stdio.h> /* for perror */

typedef struct{
  int *tab;
  size_t size; /* Prefer using size_t for (memory) sizes over using a 
                  signed int. */
} arr;

void changeSizeDyn(arr *parr, size_t size)
{
  if (!parr && !parr->tab)
  {
    errno = EINVAL;
  }
  else
  {
    arr tmp = {
      malloc(size * sizeof *tmp.tab),
      size
    };

    if (tmp.size && !tmp.tab)
    {
      perror("malloc() failed");
    }
    else
    {      
      for (
        size_t m = (tmp.size < parr->size) ?tmp.size :parr->size, i = 0;
        i < m; 
        ++i)
      {
        tmp.tab[i] = parr->tab[i];
      }

      free(parr->tab);

      *parr = tmp;

      errno = 0;
    }
  }
}

/* A main() to test the above: */
int main(void)
{
  const size_t s = 42;
  arr a = {
    malloc(s * sizeof *a.tab),
    s
  };

  if (a.size && !a.tab)
  {
    perror("malloc() failed");
    exit(EXIT_FAILURE);
  }

  /* populate a.tab[0] to a.tab[a.size - 1] here. */

  changeSizeDyn(&a, 43);
  if (0 != errno)
  {
    perror("changeSizeDyn() failed");
    exit(EXIT_FAILURE);
  }

  /* Use a.tab[0] to a.tab[a.size - 1] here. */

  free(a.tab);
  a.size = 0;
}

答案 4 :(得分:-2)

with tf.Session(graph=self.graph) as sess:
    sess.run(self.train_step,
             feed_dict={
                 self.lstm_output_ph: self.last_output,
                 self.reward_ph: reward,
                 self.previous_q_ph: previous_q
             })

和您的类型(略有变化)

void *onlymallocrealloc(void *ptr, size_t oldsize, size_t newsize)
{
    void *newmem = malloc(newsize);

    if(ptr && newmem)
    {
        memcpy(newmem, ptr, oldsize);
        free(ptr);
    }
    return newmem;
}

编辑该功能是否必须为空

typedef struct{
    int size;
    int tab[];
}arr;


arr *onlymalloc(arr *ptr, size_t newsize)
{
    ptr = onlymallocrealloc(ptr, ptr -> size * sizoef(ptr -> tab[0]) + sizeof(*ptr), newsize * sizoef(ptr -> tab[0]) + sizeof(*ptr));

    if(ptr)
    {
        ptr -> size = newsize;
    }
    return ptr;
}