我们用来表示一个带有符号*
的指针。迭代程序,我们得到一个" double"指针**
,"三重"指针***
,更一般地说,是" d-dimensional"指针(对于每个d正自然数)。
问题:给定d作为输入,将S定义为d维指针。
因为我几天前才开始研究动态结构,不幸的是我对这个问题有点麻烦。 有没有人有建议/提示?
提前谢谢你,我为我可能太基本的问题道歉。
Ps:我使用了"指针"没有指明它的类型只是为了简洁。
答案 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;
答案 1 :(得分:3)
有三种不同的方法可以解决这个问题:
您的d
是编译时常量。在这种情况下,dasblinkenlight has already given the solution。
hacky-C解决方案:只需使用强制转换返回指针类型:
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;
}
我认为这种方法最干净,最灵活。但是,它需要大量的样板代码才能使它飞行。
答案 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;
}