2015-12-21 61 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; 
}