2015-12-21 28 views
4

我们用它来指示一个带有符号*的指针。迭代该过程,我们获得“双”指针**,“三重”指针***,以及更一般地,“d维”指针(对于每个d正自然数)。创建一个d维指针

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

因为我几天前才开始研究动态结构,所以我很不幸地遇到了这个问题。 有没有人有建议/提示?

非常感谢您的提问,对于我可能过于基本的问题表示歉意。 Ps:为了简洁起见,我使用了“指针”一词,但没有指定其类型。

+0

绝不要使用超过两级间接指针的指针,否则我会建议甚至不使用指针直到除非必要。 – haccks

+0

听起来好像你想要一个d维数据结构,可能是一个带有查找函数的平面数组,而不是d级指针。你不能使间接程度(星号数)动态化。 –

+0

@haccks - *永远不要使用超过两级间接指针的指针...... *你将如何创建一个可变大小的三维数组? –

回答

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

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

如果不是具有任意数量的间接级别的指针,它可能在运行时在函数上表示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); 

一个可变参数的解决方案可能是可能的。

解引用数组需要类似的东西。这将返回元素的地址解引用:

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维数组。

2

基本上*的数字表示达到变量的间接数。所以你必须创建d indirections。我认为这没有实际应用 - 这是一个休闲问题的答案。

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

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

要动态创建这样的结构,则可以通过的malloc(与任何已知类型的替换T)做到这一点,以及 - 因为可能没有指定的*动态的指针的数目 - 需要一些C黑客攻击。

所以,再次这不是推荐,是一个特别糟糕的设计,尤其是对于没有经验的C语言开发。目的是显示它可以动态地完成,无论的值如何。

说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设置为和应用上面(比如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 
3

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

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

  2. 的哈克-C的解决方案:只需使用强制取回指针类型:

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

    我不推荐这种方法,虽然。它太脏了。

  3. 你实现你d -level指针作为用户定义类型:

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

    我认为这种方法最干净,最灵活的一个。然而,它需要权衡大量的样板代码才能使其飞行。

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