-2

Say I have an array of void pointers

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?

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.

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;
 }
}
orange_juice
  • 191
  • 1
  • 11
  • You might be better off using something like `malloc(sizeof(void*) * 10)` (replacing 10 with however many elements you want in your array). – neuronaut Sep 24 '15 at 22:56
  • 1
    In C there is not stack and Heap. The standard (Section 6.2.4) speaks only about **storage durations for objects**. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf – Michi Sep 24 '15 at 22:58
  • Whoops yeah that was an issue but I replaced it with malloc(sizeof(void*)*40) and I'm still having the same issue. (arr->content pointing to null) – orange_juice Sep 24 '15 at 23:02
  • 1
    @Michi that doesn't really matter here. Show some C implementation that *doesn't* use heap for dynamic allocations .... –  Sep 24 '15 at 23:04
  • Probably you didn't understood my point. There is stack and heap in the same manner as "call by reference" in **C** – Michi Sep 24 '15 at 23:08
  • @orange_juice Ok maybe I shouldn't have posted an answer because from the current shape of your question, it's a) unclear what you really want to achieve and b) impossible to reproduce the actual problem. Please don't edit quirks already spotted in your posted code but better add more info with your edits. A [MCVE](http://stackoverflow.com/help/mcve) might help a lot here. –  Sep 24 '15 at 23:21
  • @orange_juice Are you trying to place the pointers in the heap or what the pointers point to? – Corb3nik Sep 24 '15 at 23:59
  • @FelixPalmen: The stack can easily be replaced by using dynamically allocated memory - from a heap. And dynamic allocation can use a pool-based approach instead of a heap. – too honest for this site Sep 25 '15 at 01:58
  • What do you mean with "original `arr *`? `arr` cannot change as it is an array.and the construct `arr *` is not valid anyway (what would that be?). And what is the reason to use `void *` anyway? You hate your compiler and prefer checking types yourself? – too honest for this site Sep 25 '15 at 02:03
  • You never store `new_array` anywhere and you have no code which uses its value, so I do not see what you are asking. Your code does copy pointers into the array you allocated but you never use it. – M.M Sep 25 '15 at 05:49
  • "Why isn't this code working?" questions should include a [MCVE](http://stackoverflow.com/help/mcve) – M.M Sep 25 '15 at 05:51

2 Answers2

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:

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:

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

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

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

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 ...

  • @DavidC.Rankin I didn't create any compilable code, just snippets for explanation. What are you talking about? –  Sep 24 '15 at 23:08
  • Sorry for not being more clear. In my actual code I have a struct 'hyrbid_array' containing an element 'void** content'. I take a pointer to an instance of this structure and manipulate the contents element accordingly, the 'void*' taken as an argument in the stackTheap function was just a typo but not in my actual code. As for what I'm trying to achive, I'm basically trying to make an array structure that is stack allocated up to a certain size and when that size is passed it uses the heap for dynamic allocation. – orange_juice Sep 24 '15 at 23:12
  • @FelixPalmen -- I don't know what I was thinking, good question and suggestions. – David C. Rankin Sep 25 '15 at 05:47
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.

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)

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:

#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)
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85