关于C中的静态和动态数组的困惑

时间:2013-06-12 16:00:34

标签: c pointers

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 中,实际指向的是什么(数据+偏移量)?是不是指向 arr 这是指向字符串第一个元素的char指针?但是在函数 g 中,(data + offset)也指向了char指针。那么为什么必须使用两种不同的方法来完成同样的任务呢?

5 个答案:

答案 0 :(得分:3)

在这两种情况下data+offset都指向结构成员。

但是让我们看看结构的结构。它由

组成
+-----+--------------------------------------------+
| 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        |
+-----+--------------------------------------------+

和内存中的其他位置是使用malloc分配的100字节块。

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

答案 1 :(得分:1)

您必须向编译器提供有关函数fg中指针类型的信息,不能对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);
}

答案 2 :(得分:1)

  

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

这是您混淆的主要原因。 arr不是指针,而是数组。数组不是指针。同时,str是一个指针。 “数组”和“指针”是两个完全不同的东西。他们几乎没有任何共同之处。这正是你必须以不同方式与他们合作的原因。

在所谓的值上下文中(即用作 rvalues 时),数组和指针的行为非常相似,但这纯粹是肤浅的相似性。他们立即揭示了他们在所谓的对象上下文中的主要差异(即当用作 lvalues 时)。在您的特定示例中,您的成员访问代码是对象上下文的示例,这就是您必须仔细观察arrstr之间差异的原因。

阵列和指针之间的差异问题已经多次讨论过了。我认为没有理由在此重复。只需在SO上搜索“数组指针差异”即可。或阅读必要的常见问题

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

P.S。另请注意,C语言不支持void *指针上的指针算法。您的所有(data + offset)表达式均无效。你想要做的是((char *) data + offset)。要将datavoid *转换为char *,才能使用字节偏移执行点算术。

答案 3 :(得分:0)

在你的结构中,在(推测)偏移量4处,是一个一个接一个的10个字节的列表,包含使得' Hello&#39 ;;所以(data + 4)是char的指针,需要相应地进行dcoded(即char *)。

然而,在这10个字节之后,出现一些字节使得缓冲区的地址在某处,即那些字节是' char *' (你这样定义了它们),所以数据+偏移有一个指针指向一个char指针或char **

可能令人困惑的是两者都

strcpy(test.arr," Hello");
  strcpy(test.str," World!");

的工作。

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

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

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

答案 4 :(得分:0)

  

在函数f中,实际指向的是什么(数据+偏移量)?

它指向结构对象的'arr'成员(如果你假设GCC的void指针算术的语义)。

  

它是否指向arr,它是指向字符串第一个元素的char指针?

arr是一个char数组,而不是char指针。

  

但是在函数g中,(data + offset)也指向了char指针。

在这种情况下,它指向一个char指针,是的。

  

那么为什么必须使用两种不同的方法来完成同样的任务呢?

指针指向两个不同的东西 - 一个指向char指针(它本身指向一个char数组),另一个指向char数组。在第一种情况下还有一个间接层次。