创建一个d维指针

时间:2015-12-21 14:57:40

标签: c pointers

我们用来表示一个带有符号*的指针。迭代程序,我们得到一个" double"指针**,"三重"指针***,更一般地说,是" d-dimensional"指针(对于每个d正自然数)。

  

问题:给定d作为输入,将S定义为d维指针。

因为我几天前才开始研究动态结构,不幸的是我对这个问题有点麻烦。 有没有人有建议/提示?

提前谢谢你,我为我可能太基本的问题道歉。

Ps:我使用了"指针"没有指明它的类型只是为了简洁。

5 个答案:

答案 0 :(得分:5)

只要满足两个条件,此问题就在C中有解决方案:

  • d的值在编译时已知,
  • d具有预定义的限制,例如10

您可以通过定义一系列和"粘贴"来解决此问题。 d的值作为标记:

#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**********

现在你可以声明d - 像这样的维度指针:

D_PTR(5,int) ptr5 = NULL;

Demo.

答案 1 :(得分:3)

有三种不同的方法可以解决这个问题:

  1. 您的d是编译时常量。在这种情况下,dasblinkenlight has already given the solution

  2. hacky-C解决方案:只需使用强制转换返回指针类型:

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

    我不推荐这种方法,但。这太脏了。

  3. 您将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;
    }
    

    我认为这种方法最干净,最灵活。但是,它需要大量的样板代码才能使它飞行。

答案 2 :(得分:2)

基本上*的数量表示到达变量的间接数。所以你必须创建 d 间接。我认为这没有实际应用 - 这是对娱乐性问题的回答。

C中的间接是一个地址,一个指针。创建 d 间接意味着创建 d 地址以获取可变数据(分配给T类型变量的空间)。

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

要动态创建这样的结构,您可以通过 malloc (用任何已知类型替换T)来实现,并且 - 因为您可能没有动态地指定*的数量指针 - 需要一些C黑客攻击。

所以,再次,这不是推荐的东西,特别是糟糕的设计,特别是对于没有经验的C开发人员。目的是表明它可以动态完成,无论 d 的值是什么。

说T是 double

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的函数(此处为double),取S值和d,操作d indirections并返回变量

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

答案 3 :(得分:1)

  

问题:给定这样的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 ] ) ) );
    }
}

在C ++中要容易得多,因为你可以为数组对象提供一个[]运算符并嵌套它们来构建N维数组。

答案 4 :(得分:1)

您可以通过链接尽可能多的void **指针来创建d-indirection指针的运行时等效项。然后可以用这种方式构建稀疏数组:

#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;
}