使指针指向C中另一个指针指向的内容

时间:2011-05-06 19:31:24

标签: c math memory pointers struct

我无法在标题中描述我的问题,但基本上我需要一些指针算法的帮助。假设你有一个像下面这样的结构。然后你得到一个指针,指向内存中结构中的long。让我们说指针是 * p 。所以我会做 p + = sizeof(void *)来得到p在下一个指针的位置。现在,我如何实际指向下一个指向的内容,而不仅仅指向下一个指针在内存中的位置?

struct freeblock {
  long s; 
  // <--- THE POINTER WOULD BE POINTING HERE
  struct freeblock *prev;
  struct freeblock *next;
} 

6 个答案:

答案 0 :(得分:2)

试试这个:

void *p; /* points to prev now */
struct freeblock *p1;

p = ((char *)p)+sizeof(struct freeblock *); /* advance p to next */
p1 = *(struct freeblock **)p; /* take whatever is in next */

p1指向下一个相同的位置。

很少解释 - 在C中键入指针。在指针中添加1意味着将sizeof(type)添加到实际地址,因此您需要将指针指向正确的类型,或者如果您需要手动算术,则需要指向char *,因为sizeof(char)是1。

答案 1 :(得分:2)

这有可能是一个棘手的问题。你真的不想在你的结构中做指针运算。原因是Struct Alignment。如果您有这样的结构,会发生什么:

struct a{
  char x; //address 0x8
  //potentially 3 bytes lost here:
  int y; //address 0x12
}

y在x之后不会开始一个字节。为了保持对齐,所以y开始,例如,地址是4的倍数,在x之后会添加一些填充字节。

如果你有一个结构实例0x08的地址并添加一个字符的大小,产生(0x09)你不会得到y 0x12的开头,你会得到一些垃圾数据&#39 ; s部分垃圾和部分y。

在这种情况下你应该没问题,因为相同的类型是相继的,你可以这样做:

freeblock* p = s.prev;
p += sizeof(p);
freeblock next = *p;

你真的想得到一个指向结构的指针,让编译器为你计算偏移量。

答案 2 :(得分:1)

假设您只知道p的当前值,并且它指向prev实例的struct freeblock字段。同时,请记住“长时间”地址可能与prev字段的地址不同,例如如果sizeof(long)==4和指针对齐为8个字节(即true for some 64-bit platforms);请参阅Paul Rubel的解释答案。

现在您需要在同一个实例中获取next的值,然后取消引用它。符合标准的解决方案应该涉及offsetof() macro

void * p;
...
size_t delta = offsetof(struct freeblock,next)-offsetof(struct freeblock,prev);
p = (void*) *(struct freeblock**)((char*)p+delta);

因此,您首先在prev的帮助下计算nextoffsetof()字段的地址之间的差异,然后将p转换为指向char的指针以便正确添加delta并获取next字段的地址,然后将其转换为指向指针到freeblock的指针,取消引用该地址以获得所需的值,最后将值赋给p转换为指向void的指针(可以省略,但我会将其保留在生产代码中)。

答案 3 :(得分:0)

也许你正试图取消引用p,就像这样:

 char *p;
 struct freeblock *x;
// you got the value for p here somehow.
 x = *((struct freeblock **)p);
//  now you can access the fields:
 if (x->next != 0)
 { //...
 }

请注意,我选择保持我的意识,即x的类型与p的类型不同。你可以将x和p都声明为void *,但是你必须先将x转换为'((struct freeblock *)x)'才能进入字段。

由于编译器对齐问题等原因,这无法保证正常工作。当然,这是设计代码的一种可怕方法。

答案 4 :(得分:0)

指针应指向特定的类型变量,您无法对void*执行aritmethic操作。

但假设它是一些有效的数据类型,那么p++p += 1将完成这项工作,请注意,开始将指针指向不同类型是危险的。

struct a{
  long s; 
  int d;// <--- THE p POINTER WOULD BE POINTING HERE
  struct freeblock *prev;
  struct freeblock *next;
} 

p + = 1; //就像d + = 1 * sizeof(int);

struct a{
  long s; 
  int d;
  struct freeblock *prev; // <--- now p points here
  struct freeblock *next;
} 

答案 5 :(得分:0)

你说“p在next指针的位置”,你想“指出next指向的地方”:

我将假设pchar*

p = (char*) *((struct freeblock**) p);

简要说明:

由于p指向nextp正在“充当”指向struct freeblock*struct freeblock**的指针。要获取struct freeblock**所指向的值,您只需取消引用它(导致另一个指针,但类型错误)。将结果指针转换为p的正确类型,然后设置。