Creating a d-dimensional pointer

We use to indicate a pointer with a symbol *. Iterating the procedure, we get a “double” pointer **, a “triple” pointer ***and, in a more general sense, a “d-dimensional” pointer (for each d positive integer).

Task: Given a d such as an input, define S as a d-dimensional pointer.

Since I began to study dynamic structures only a few days ago, unfortunately, I am not able to cope with this problem a bit. Does anyone have a suggestion / hint?

Thanks in advance, and my apologies for my probably too basic question.

Ps: I used the word "pointer" without specifying its type for brevity only.

+4
source share
5 answers

This problem has a solution in C if two conditions are true:

  • Value is dknown at compile time and
  • dhas a predetermined limit, for example. 10

You can solve this problem by defining a series of macros and "pasting" the value das a token:

#define D_PTR(d,T) D_PTR##d(T)
#define D_PTR0(T) T
#define D_PTR1(T) T*
#define D_PTR2(T) T**
#define D_PTR3(T) T***
...
#define D_PTR10(T) T**********

Now you can declare d-dimension pointers as follows:

D_PTR(5,int) ptr5 = NULL;

Demo version

+5
source

There are three different ways to solve this problem:

  • Yours dis the compile-time constant. For this case, dasblinkenlight has already provided a solution .

  • Hacky-C solution: just use a cast to return to pointer type:

    double* dereferenceDLevels(double* pointer, int d) {
        for(; d--; ) pointer = *(double**)pointer;
        return pointer;
    }
    

    , . .

  • d :

    typedef struct nLevelPointer {
        int n;
        union {
            nLevelPointer* pointer;
            double value;
        };
    } nLevelPointer;
    
    double nLevelPointer_dereference(nLevelPointer* me) {
        for(int i = me->n; i--; ) me = me->pointer;
        return me->value;
    }
    

    . , , .

+3

* . d-. , - .

C , . d- d- (, T).

p(d) -> p(d-1) -> ... -> p(1) -> variable

​​, malloc ( T ), - * - C.

, , C. , , , d.

, T

int d = ...; // from input (d >= 1)
double variable;

double **S = malloc(sizeof(double *) * d); // array of pointers to pointer

S[d-1] = &variable; // last address points to target
int i;
for(i=d-2 ; i>=0 ; i--) S[i] = (double *)&S[i+1]; // previous address
                                                  // points to next location

C, S - **, .

d 4 (, T ),

double variable is at address 0100 (decimal), value 3.14
S address given by malloc at  1000
a pointer size being             4
a double  size being             8

variable
v
[8 bytes double value 3.14]
^
0100

S
v
[1004][1008][1012][0100]
^                 ^
1000              1012

, /? , T ( ), S d, d

double getvariable(double **S, int d) {
    while (--d > 0) S = (double **)*S; // d-1 iterations
    return *(double *)*S;
}

printf("%lf\n", getvariable(S, d)); // 3.14

, d == 4

double ****p = (double ****)*S;
printf("%lf\n", ****p);             // 3.14
+2

: d , S d- .

C N- , . ( , ):

void *allocateArray( unsigned int N, size_t elemSize, unsigned int *dimensions )
{
    if ( N == 1U )
    {
        return( malloc( elemSize * dimensions[ 0 ] ) )
    }

    void *array = malloc( sizeof( void * ) * dimensions[ 0 ] );
    for ( unsigned ii = 0; ii < dimensions[ 0 ]; ii++ )
    {
        array[ ii ] = allocateArray( N - 1, elemSize, &( dimensions[ 1 ] ) );
    }

    return( array );
}

, N- .

:

unsigned dims[] = { 5,7,8,9 };
unsigned d = sizeof( dims ) / sizeof( dims[ 0 ] );
size_t elemSize = sizeof( double );

void *array = allocateArray( d, elemSize, dims );

varargs.

- . :

void *dereferenceArray( void *array, unsigned int N,
    size_t elemSize, unsigned int *element )
{
    if ( N == 1U )
    {
        char *tmp = array;
        return( tmp + ( elemSize * element[ 0 ] ) );
    }
    else
    {
        void **tmp = array;
        return( dereferenceArray( tmp[ element[ 0 ] ],
            N - 1, elemSize, &( element[ 1 ] ) ) );
    }
}

In C ++, it would be much simpler, since you could provide an operator to []your array object and nest them in N-dimensional arrays.

+1
source

You can create the d-direction pointer runtime equivalent by combining as many void ** pointers as you need. Then a sparse array can be built:

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

int main(int argc, char *argv[])
{
    if (argc < 4)
    {
        printf("Call this passing d (dimensions), n (elements for each dim), u (used elements) as parameters\n");
        return 0;
    }
    int d = atoi(argv[1]);
    assert(d > 0);
    int n = atoi(argv[2]);
    assert(n > 0);
    int u = atoi(argv[3]);
    assert(u < n * d);

    // Creating
    void *root = malloc(sizeof(void *) * n);
    memset(root, 0, sizeof(void *) * n);
    srand(time(NULL));
    int i, p, c;
    void **cursor;
    for (int c = 0; c < u; ++c)
    {
        cursor = root;
        for (i = 0; i < d; ++i)
        {
            p = rand() % n; 
            if (cursor[p] == NULL)
            {
                cursor[p] = malloc(sizeof(void *) * n);
                memset(cursor[p], 0, sizeof(void *) * n);
            }
            cursor = cursor[p];
        }
        p = rand() % n;
        if (cursor[p] == NULL)
            cursor[p] = "Hello";
        else
          --c;
    }
    // Traversing
    struct SE
    {
        void * *s;
        int p;
    };
    struct SE *stack = malloc(sizeof(struct SE) * (d + 1));
    for (cursor = root, p = 0, i = 0; ; ++p)
    {
        if (p == n)
        {
            if (i == 0)
                break;
            cursor = stack[--i].s;
            p = stack[i].p;
        }
        else if (cursor[p] != NULL)
        {
            if (i < d)
            {
                stack[i].s = cursor;
                stack[i++].p = p;
                cursor = cursor[p];
                p = -1;
            }
            else
            {
                printf("root");
                for (c = 0; c < i; ++c)
                    printf("[%d]->", stack[c].p);
                printf("[%d]=\"%s\"\n", p, cursor[p]);
            }
        }
    }

    // Tearing down
    for (cursor = root, p = 0, i = 0; ; ++p)
    {
        if (p == n)
        {
            if (i == 0)
                break;
            cursor = stack[--i].s;
            p = stack[i].p;
            free(cursor[p]);
        }
        else if (cursor[p] != NULL && i < d)
        {
            stack[i].s = cursor;
            stack[i++].p = p;
            cursor = cursor[p];
            p = -1;
        }
    }
    free(root);
    free(stack);
    return 0;
}
+1
source

Source: https://habr.com/ru/post/1621129/


All Articles