如何将元素从堆栈中分配的void指针数组传递给堆?

时间:2021-03-19 21:42:19

Say I have an array of void pointers

假设我有一个void指针数组

void* arr[10];

and I want to transfer that to the heap. I assume I would just allocate a new pointer array using malloc and then start copying individual elements no?

我想把它转移到堆。我假设我只是使用malloc分配一个新的指针数组,然后开始复制单个元素没有?

void stackTheap(void** arr)
{
   void** arr_new = malloc(20*sizeof(void*));
   for(int i = 0; i < 10; i++)
   {
       arr_new[i] = arr[i];
   }
}

But for some reason as soon as my program reaches the for loop the original arr* points to zero.

但由于某种原因,只要我的程序到达for循环,原始的arr *就会指向零。

Heres my actual code just in case its some stupid syntax error:

继承了我的实际代码,以防它出现一些愚蠢的语法错误:

void regularTodynamic(hybrid_array* arr)
 {
 if(arr->dynamic_mode_flag == 0)
 {
    void** new_array = malloc(sizeof(void*)*40);
    for(int i = 0; i < arr->elem_count; i++)
    {
        new_array[i] = arr->content[i];
    }   

    arr->total_size = 30;
    arr->dynamic_mode_flag = 1;
 }
}

2 个解决方案

#1


1  

From the code, I guess only a partial answer is possible -- referring to your first snippet here only:

从代码中,我想只有部分答案是可能的 - 仅在此处引用您的第一个代码段:

void* arr[10];

This is an array of 10 void pointers -- so far so good, but this:

这是一个包含10个void指针的数组 - 到目前为止一直很好,但是这个:

void stackTheap(void* arr) { ...

will just take a single void pointer. It should probably be

只需要一个空指针。它可能应该是

void stackTheap(void** arr) { ...

Then for your copy, you allocate like this:

然后为您的副本,您分配如下:

void** arr_new = malloc(20);

How do you know you need these 20 bytes? In fact, on a common 32bit architecture, you would already need 40. If you're really working with fixed array sizes, this should be:

你怎么知道你需要这20个字节?事实上,在一个常见的32位架构上,你已经需要40个。如果你真的在使用固定数组大小,那应该是:

void** arr_new = malloc(10 * sizeof(void *));

The sizeof(void *) will be e.g. 4 on x86, 8 on amd64, etc ...

sizeof(void *)将是例如x86上4,amd64上8,等等...

This is still very limited, suggest to give your function a size_t argument for passing the actual array length:

这仍然是非常有限的,建议给你的函数一个size_t参数来传递实际的数组长度:

void stackTheap(void** arr, size_t nelem)
{
    void** arr_new = malloc(nelem * sizeof(void *));
    ...

All in all, it remains a mystery to me what you actually try to achieve ...

总而言之,对我来说,你真正想要达到的目标仍然是个谜......

#2


0  

If I understand that you want to handle changing the storage for an array of pointers currently with static storage (on the stack in common terms) to a newly allocated block of memory, then you need to consider whether you simply want to change the storage of the pointers (referred to at times as a shallow copy) or whether you want to change the storage of both the pointers as well as the data pointed to (a deep copy).

如果我理解你想要处理当前带有静态存储(在通用术语中的堆栈)的指针数组的存储更改为新分配的内存块,那么你需要考虑是否只是想改变存储指针(有时称为浅拷贝)或者是否要更改指针的存储以及指向的数据(深拷贝)。

While this is impossible to accomplish without passing more information to your stackTheap function, if you provide it with the number of pointers you are dealing with, and the size of the data type pointed to, you can accomplish either a shallow or deep copy depending on what you pass to stackTheap.

虽然如果不向stackTheap函数传递更多信息是不可能实现的,如果你提供了你正在处理的指针数量,以及指向的数据类型的大小,你可以完成一个浅的或深的复制,具体取决于你传递给stackTheap的是什么。

The following is just one example to approach a function that will either perform a shallow copy (if dsz is 0), or a deep copy if dsz is passed a value. (there are many ways to pass various flags and parameters to accomplish this, this is just one approach)

以下只是一个接近函数的示例,该函数将执行浅拷贝(如果dsz为0),或者如果dsz传递值则执行深拷贝。 (有很多方法可以传递各种标志和参数来实现这一点,这只是一种方法)

Below, the example shows a shallow copy of parr (pointer array) to narr (new array). It then provides an example of a deep copy from parr to narr2 with intermediate type pruning to char using the same function. I'm not certain this is exactly what you are looking for, but if so and you have questions, just let me know:

下面,该示例显示了parr(指针数组)到narr(新数组)的浅表副本。然后它提供了一个从parr到narr2的深拷贝的示例,其中使用相同的函数将中间类型修剪为char。我不确定这正是你想要的,但如果有,你有疑问,请告诉我:

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

#define MAXI 10

/* void copy array 'arr' of type 'sz' to 'arr_new'. if 'arr' is a 
 * pointer to an array of pointers to type 'dsz', a deep copy is 
 * required to copy contents pointed to by each of the array of 
 * pointers to a newly allocate block of memory. 
 * For a shallow copy, 'dsz = 0'.
 */
void *stackTheap (void *arr, size_t n, size_t sz, size_t dsz)
{
    if (!arr) return NULL;
    void* arr_new = malloc (n * sz);
    memcpy (arr_new, arr, n * sz);
    if (dsz) {
        size_t i;
        for (i = 0; i < n; i++) {
            char **a = (char **)arr;
            char **n = (char **)arr_new;
            n[i] = malloc (dsz);
            memcpy (n[i], a[i], dsz);
        }
    }
    return arr_new;
}

int main (void) {

    void *parr[MAXI] = {NULL};   /* void pointer array       */
    void **narr = {NULL};        /* new array (shallow copy) */
    void **narr2 = {NULL};       /* new array (deep copy)    */
    int arr[MAXI] = {10,20,30,40,50,60,70,80,90,100};   /* array */
    int i;

    /* assigned pointers */
    for (i = 0; i < MAXI; i++)
        parr[i] = &arr[i];

    /* print addressess of pointers and data on stack */
    printf ("\n pointers stored on the stack\n");
    for (i = 0; i < MAXI; i++)
        printf ("  parr[%2d] : %3d    %p -> %p\n", i, *(int *)parr[i], 
                &parr[i], parr[i]);

    /* shallow copy 'parr' to 'narr' */
    narr = stackTheap (parr, MAXI, sizeof (int*), 0);

    /* print address of pointers on heap data on stack */
    printf ("\n pointers allocated on the heap\n"
            " (pointing to original values on stack)\n");
    for (i = 0; i < MAXI; i++)
        printf ("  narr[%2d] : %3d    %p -> %p\n", i, *(int *)narr[i], 
                &narr[i], narr[i]);

    /* deep copy 'parr' to 'narr2' */
    narr2 = stackTheap (parr, MAXI, sizeof (int*), sizeof (int));

    /* print addresses of pointers and data on heap */
    printf ("\n pointers and data allocated on the heap\n");
    for (i = 0; i < MAXI; i++)
        printf ("  narr2[%2d] : %3d    %p -> %p\n", i, *(int *)narr2[i], 
                &narr2[i], narr2[i]);

    /* free memory here */
    free (narr);

    for (i = 0; i < MAXI; i++)
        free (narr2[i]);
    free (narr2);

    return 0;
}

Output

$ ./bin/void_pcpy

 pointers stored on the stack
  parr[ 0] :  10    0x7fff101e1a90 -> 0x7fff101e1a60
  parr[ 1] :  20    0x7fff101e1a98 -> 0x7fff101e1a64
  parr[ 2] :  30    0x7fff101e1aa0 -> 0x7fff101e1a68
  parr[ 3] :  40    0x7fff101e1aa8 -> 0x7fff101e1a6c
  parr[ 4] :  50    0x7fff101e1ab0 -> 0x7fff101e1a70
  parr[ 5] :  60    0x7fff101e1ab8 -> 0x7fff101e1a74
  parr[ 6] :  70    0x7fff101e1ac0 -> 0x7fff101e1a78
  parr[ 7] :  80    0x7fff101e1ac8 -> 0x7fff101e1a7c
  parr[ 8] :  90    0x7fff101e1ad0 -> 0x7fff101e1a80
  parr[ 9] : 100    0x7fff101e1ad8 -> 0x7fff101e1a84

 pointers allocated on the heap
 (pointing to original values on stack)
  narr[ 0] :  10    0x1e00010 -> 0x7fff101e1a60
  narr[ 1] :  20    0x1e00018 -> 0x7fff101e1a64
  narr[ 2] :  30    0x1e00020 -> 0x7fff101e1a68
  narr[ 3] :  40    0x1e00028 -> 0x7fff101e1a6c
  narr[ 4] :  50    0x1e00030 -> 0x7fff101e1a70
  narr[ 5] :  60    0x1e00038 -> 0x7fff101e1a74
  narr[ 6] :  70    0x1e00040 -> 0x7fff101e1a78
  narr[ 7] :  80    0x1e00048 -> 0x7fff101e1a7c
  narr[ 8] :  90    0x1e00050 -> 0x7fff101e1a80
  narr[ 9] : 100    0x1e00058 -> 0x7fff101e1a84

 pointers and data allocated on the heap
  narr2[ 0] :  10    0x1e00070 -> 0x1e000d0
  narr2[ 1] :  20    0x1e00078 -> 0x1e000f0
  narr2[ 2] :  30    0x1e00080 -> 0x1e00110
  narr2[ 3] :  40    0x1e00088 -> 0x1e00130
  narr2[ 4] :  50    0x1e00090 -> 0x1e00150
  narr2[ 5] :  60    0x1e00098 -> 0x1e00170
  narr2[ 6] :  70    0x1e000a0 -> 0x1e00190
  narr2[ 7] :  80    0x1e000a8 -> 0x1e001b0
  narr2[ 8] :  90    0x1e000b0 -> 0x1e001d0
  narr2[ 9] : 100    0x1e000b8 -> 0x1e001f0

Memory Check

$ valgrind ./bin/void_pcpy
==18688== Memcheck, a memory error detector
==18688== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==18688== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==18688== Command: ./bin/void_pcpy
==18688==

<snip>
==18688==
==18688== HEAP SUMMARY:
==18688==     in use at exit: 0 bytes in 0 blocks
==18688==   total heap usage: 12 allocs, 12 frees, 200 bytes allocated
==18688==
==18688== All heap blocks were freed -- no leaks are possible
==18688==
==18688== For counts of detected and suppressed errors, rerun with: -v
==18688== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

#1


1  

From the code, I guess only a partial answer is possible -- referring to your first snippet here only:

从代码中,我想只有部分答案是可能的 - 仅在此处引用您的第一个代码段:

void* arr[10];

This is an array of 10 void pointers -- so far so good, but this:

这是一个包含10个void指针的数组 - 到目前为止一直很好,但是这个:

void stackTheap(void* arr) { ...

will just take a single void pointer. It should probably be

只需要一个空指针。它可能应该是

void stackTheap(void** arr) { ...

Then for your copy, you allocate like this:

然后为您的副本,您分配如下:

void** arr_new = malloc(20);

How do you know you need these 20 bytes? In fact, on a common 32bit architecture, you would already need 40. If you're really working with fixed array sizes, this should be:

你怎么知道你需要这20个字节?事实上,在一个常见的32位架构上,你已经需要40个。如果你真的在使用固定数组大小,那应该是:

void** arr_new = malloc(10 * sizeof(void *));

The sizeof(void *) will be e.g. 4 on x86, 8 on amd64, etc ...

sizeof(void *)将是例如x86上4,amd64上8,等等...

This is still very limited, suggest to give your function a size_t argument for passing the actual array length:

这仍然是非常有限的,建议给你的函数一个size_t参数来传递实际的数组长度:

void stackTheap(void** arr, size_t nelem)
{
    void** arr_new = malloc(nelem * sizeof(void *));
    ...

All in all, it remains a mystery to me what you actually try to achieve ...

总而言之,对我来说,你真正想要达到的目标仍然是个谜......

#2


0  

If I understand that you want to handle changing the storage for an array of pointers currently with static storage (on the stack in common terms) to a newly allocated block of memory, then you need to consider whether you simply want to change the storage of the pointers (referred to at times as a shallow copy) or whether you want to change the storage of both the pointers as well as the data pointed to (a deep copy).

如果我理解你想要处理当前带有静态存储(在通用术语中的堆栈)的指针数组的存储更改为新分配的内存块,那么你需要考虑是否只是想改变存储指针(有时称为浅拷贝)或者是否要更改指针的存储以及指向的数据(深拷贝)。

While this is impossible to accomplish without passing more information to your stackTheap function, if you provide it with the number of pointers you are dealing with, and the size of the data type pointed to, you can accomplish either a shallow or deep copy depending on what you pass to stackTheap.

虽然如果不向stackTheap函数传递更多信息是不可能实现的,如果你提供了你正在处理的指针数量,以及指向的数据类型的大小,你可以完成一个浅的或深的复制,具体取决于你传递给stackTheap的是什么。

The following is just one example to approach a function that will either perform a shallow copy (if dsz is 0), or a deep copy if dsz is passed a value. (there are many ways to pass various flags and parameters to accomplish this, this is just one approach)

以下只是一个接近函数的示例,该函数将执行浅拷贝(如果dsz为0),或者如果dsz传递值则执行深拷贝。 (有很多方法可以传递各种标志和参数来实现这一点,这只是一种方法)

Below, the example shows a shallow copy of parr (pointer array) to narr (new array). It then provides an example of a deep copy from parr to narr2 with intermediate type pruning to char using the same function. I'm not certain this is exactly what you are looking for, but if so and you have questions, just let me know:

下面,该示例显示了parr(指针数组)到narr(新数组)的浅表副本。然后它提供了一个从parr到narr2的深拷贝的示例,其中使用相同的函数将中间类型修剪为char。我不确定这正是你想要的,但如果有,你有疑问,请告诉我:

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

#define MAXI 10

/* void copy array 'arr' of type 'sz' to 'arr_new'. if 'arr' is a 
 * pointer to an array of pointers to type 'dsz', a deep copy is 
 * required to copy contents pointed to by each of the array of 
 * pointers to a newly allocate block of memory. 
 * For a shallow copy, 'dsz = 0'.
 */
void *stackTheap (void *arr, size_t n, size_t sz, size_t dsz)
{
    if (!arr) return NULL;
    void* arr_new = malloc (n * sz);
    memcpy (arr_new, arr, n * sz);
    if (dsz) {
        size_t i;
        for (i = 0; i < n; i++) {
            char **a = (char **)arr;
            char **n = (char **)arr_new;
            n[i] = malloc (dsz);
            memcpy (n[i], a[i], dsz);
        }
    }
    return arr_new;
}

int main (void) {

    void *parr[MAXI] = {NULL};   /* void pointer array       */
    void **narr = {NULL};        /* new array (shallow copy) */
    void **narr2 = {NULL};       /* new array (deep copy)    */
    int arr[MAXI] = {10,20,30,40,50,60,70,80,90,100};   /* array */
    int i;

    /* assigned pointers */
    for (i = 0; i < MAXI; i++)
        parr[i] = &arr[i];

    /* print addressess of pointers and data on stack */
    printf ("\n pointers stored on the stack\n");
    for (i = 0; i < MAXI; i++)
        printf ("  parr[%2d] : %3d    %p -> %p\n", i, *(int *)parr[i], 
                &parr[i], parr[i]);

    /* shallow copy 'parr' to 'narr' */
    narr = stackTheap (parr, MAXI, sizeof (int*), 0);

    /* print address of pointers on heap data on stack */
    printf ("\n pointers allocated on the heap\n"
            " (pointing to original values on stack)\n");
    for (i = 0; i < MAXI; i++)
        printf ("  narr[%2d] : %3d    %p -> %p\n", i, *(int *)narr[i], 
                &narr[i], narr[i]);

    /* deep copy 'parr' to 'narr2' */
    narr2 = stackTheap (parr, MAXI, sizeof (int*), sizeof (int));

    /* print addresses of pointers and data on heap */
    printf ("\n pointers and data allocated on the heap\n");
    for (i = 0; i < MAXI; i++)
        printf ("  narr2[%2d] : %3d    %p -> %p\n", i, *(int *)narr2[i], 
                &narr2[i], narr2[i]);

    /* free memory here */
    free (narr);

    for (i = 0; i < MAXI; i++)
        free (narr2[i]);
    free (narr2);

    return 0;
}

Output

$ ./bin/void_pcpy

 pointers stored on the stack
  parr[ 0] :  10    0x7fff101e1a90 -> 0x7fff101e1a60
  parr[ 1] :  20    0x7fff101e1a98 -> 0x7fff101e1a64
  parr[ 2] :  30    0x7fff101e1aa0 -> 0x7fff101e1a68
  parr[ 3] :  40    0x7fff101e1aa8 -> 0x7fff101e1a6c
  parr[ 4] :  50    0x7fff101e1ab0 -> 0x7fff101e1a70
  parr[ 5] :  60    0x7fff101e1ab8 -> 0x7fff101e1a74
  parr[ 6] :  70    0x7fff101e1ac0 -> 0x7fff101e1a78
  parr[ 7] :  80    0x7fff101e1ac8 -> 0x7fff101e1a7c
  parr[ 8] :  90    0x7fff101e1ad0 -> 0x7fff101e1a80
  parr[ 9] : 100    0x7fff101e1ad8 -> 0x7fff101e1a84

 pointers allocated on the heap
 (pointing to original values on stack)
  narr[ 0] :  10    0x1e00010 -> 0x7fff101e1a60
  narr[ 1] :  20    0x1e00018 -> 0x7fff101e1a64
  narr[ 2] :  30    0x1e00020 -> 0x7fff101e1a68
  narr[ 3] :  40    0x1e00028 -> 0x7fff101e1a6c
  narr[ 4] :  50    0x1e00030 -> 0x7fff101e1a70
  narr[ 5] :  60    0x1e00038 -> 0x7fff101e1a74
  narr[ 6] :  70    0x1e00040 -> 0x7fff101e1a78
  narr[ 7] :  80    0x1e00048 -> 0x7fff101e1a7c
  narr[ 8] :  90    0x1e00050 -> 0x7fff101e1a80
  narr[ 9] : 100    0x1e00058 -> 0x7fff101e1a84

 pointers and data allocated on the heap
  narr2[ 0] :  10    0x1e00070 -> 0x1e000d0
  narr2[ 1] :  20    0x1e00078 -> 0x1e000f0
  narr2[ 2] :  30    0x1e00080 -> 0x1e00110
  narr2[ 3] :  40    0x1e00088 -> 0x1e00130
  narr2[ 4] :  50    0x1e00090 -> 0x1e00150
  narr2[ 5] :  60    0x1e00098 -> 0x1e00170
  narr2[ 6] :  70    0x1e000a0 -> 0x1e00190
  narr2[ 7] :  80    0x1e000a8 -> 0x1e001b0
  narr2[ 8] :  90    0x1e000b0 -> 0x1e001d0
  narr2[ 9] : 100    0x1e000b8 -> 0x1e001f0

Memory Check

$ valgrind ./bin/void_pcpy
==18688== Memcheck, a memory error detector
==18688== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==18688== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==18688== Command: ./bin/void_pcpy
==18688==

<snip>
==18688==
==18688== HEAP SUMMARY:
==18688==     in use at exit: 0 bytes in 0 blocks
==18688==   total heap usage: 12 allocs, 12 frees, 200 bytes allocated
==18688==
==18688== All heap blocks were freed -- no leaks are possible
==18688==
==18688== For counts of detected and suppressed errors, rerun with: -v
==18688== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)