4
typedef struct mystruct{
  int a;
  char arr[10];
  char *str;
}mystruct;


void f(void *data, int offset){
  char *s = (char *)(data + offset);
  printf("%s", s);
}

void g(void *data, int offset){
  char *s = *(char **)(data+offset);
  printf("%s", s);
}

int main(){
  mystruct test;
  test.a = 2;
  test.str = malloc(100);
  strcpy(test.arr, "Hello ");
  strcpy(test.str, "World!");
  f(&test, offsetof(mystruct,arr));
  g(&test, offsetof(mystruct,str));
  return 0;
}

我想知道为什么我需要两种不同的方式来打印字符串。在函数f中, (data + offset) 实际指向什么?它不是指向arr,它是指向字符串第一个元素的 char 指针吗?但是在函数g中, (data + offset) 也指向一个 char 指针。那么为什么必须使用两种不同的方法来完成相同的任务呢?

4

5 回答 5

3

在这两种情况下都data+offset指向struct 的成员

但是让我们看一下结构的结构。它包括

+-----+--------------------------------------------+
| a   | sizeof(int) probably 4 or 8 bytes          |
+-----+--------------------------------------------+
| possible padding of unknown size (probably zero) |
+-----+--------------------------------------------+
| arr | 10 bytes                                   |
+-----+--------------------------------------------+
| possible padding of unknown size (maybe 2 bytes) |
+-----+--------------------------------------------+
| str | sizeof(char*) probably 4 or 8 bytes        |
+-----+--------------------------------------------+

内存中的其他地方是一个 100 字节的块,分配有malloc.

请注意, for 的数据test.arr存储为 分配的内存中test,但存储在testfortest.str中的是另一块内存的地址。

于 2013-06-12T16:08:56.253 回答
1

您必须向编译器提供有关函数中指针类型的信息,f并且g您不能对 void 指针进行点运算。

转换data为 char 指针,printf 将起作用

void f(void *data, int offset){
  char *s = (char *)(( char*)data + offset); 
  printf("%s", s);
}

void g(void *data, int offset){
  char *s = *(char **)((char*)data+offset);   
  printf("%s", s);
}
于 2013-06-12T16:05:24.210 回答
1

在 functionf中,(data + offset)实际指向的是什么?它不是指向arr哪个是指向字符串第一个元素的 char 指针吗?

这是你困惑的主要来源。arr不是指针,是数组。数组不是指针。同时,str是一个指针。“数组”和“指针”是两个完全不同的东西。他们几乎没有共同之处。这正是为什么你必须以不同的方式与他们合作的原因。

数组和指针在所谓的值上下文中可以表现得非常相似(即当用作rvalues时),但这纯粹是表面上的相似性。它们立即揭示了它们在所谓的对象上下文中的主要区别(即,当用作值时)。在您的具体示例中,您的成员访问代码是object contextarr的示例,这就是为什么您必须仔细观察和之间的区别str

数组和指针之间的差异问题已经讨论过很多次了。我看不出有什么理由在这里重复。只需在 SO 上搜索“数组指针差异”即可。或阅读基本常见问题解答

http://c-faq.com/aryptr/index.html

PS 另请注意,C 语言不支持指针上的指针算术void *。你所有的(data + offset)表达都是无效的。你想做的是真的((char *) data + offset)。为了能够使用字节偏移执行点算术,需要datavoid *到转换。char *

于 2013-06-12T16:24:42.077 回答
0

在你的结构中,在(大概)偏移量 4 处,是一个 10 个字节的列表,一个接一个,包含使“你好”的字母;所以 (data+4) 是一个指向 char 的指针,需要进行相应的编码(即char *)。

然而,在这 10 个字节之后,有几个字节在某处构成缓冲区的地址,即这些字节是一个 'char *' (你这样定义它们),所以 data+offset 在 char 指针上有一个指针或一个char **

可能令人困惑的是,两者

strcpy(test.arr, "你好");
strcpy(test.str,“世界!”);

工作。

这是一个令人困惑的(但 C/C++ 的有用特性)。当在需要指向数组元素类型的指针的地方使用数组的名称时,编译器会将其视为指向数组第一个元素的指针。

所以test.str显然是一个指向 char 的指针(因为你是这样定义的)。 test.arr 如果情况建议,可以用作指向测试的第一个元素的指针。

当您编写strcpy(test.arr, "Hello "); 编译器假设您的意思是 strcpy(&test.arr[0], "Hello ");

于 2013-06-12T16:16:20.707 回答
0

In function f, what is (data + offset) actually pointing at?

It is pointing at the 'arr' member of the structure object (if you assume GCC's semantics for the void pointer arithmetic).

Is it not pointing to arr which is a char pointer to the first element of the string?

arr is a char array, not a char pointer.

But in function g, (data + offset) is pointing to a char pointer too.

In this case, it is pointing to a char pointer, yes.

So why two different approaches must be used to do the same task?

The pointers are to two different things - one to a char pointer (which itself points at a char array) and the other to a char array. There is one more level of indirection in the first case.

于 2013-06-12T16:19:17.163 回答