简体   繁体   English

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

[英]Confusion about static and dynamic arrays in C

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;
}

I am wondering why do I need two different ways to print strings. 我想知道为什么我需要两种不同的方式来打印字符串。 In function f , what is (data + offset) actually pointing at? 在函数f中 ,实际指向的是什么(数据+偏移量)? Is it not pointing to arr which is a char pointer to the first element of the string? 是不是指向arr哪个是指向字符串第一个元素的char指针? But in function g , (data + offset) is pointing to a char pointer too. 但是在函数g中 ,(data + offset)也指向了char指针。 So why two different approaches must be used to do the same task? 那么为什么必须使用两种不同的方法来完成同样的任务呢?

In both cases data+offset points to a member of the struct . 在这两种情况下, data+offset指向结构成员

But lets look at the structure of the the struct. 但是让我们看看结构的结构。 It consists of 它包括

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

and elsewhere in memory is a block of 100 byte allocated with malloc . 内存中的其他地方是用malloc分配的100字节块。

Notice that the data for test.arr is stored in the memory allocated for test , but the thing stored in test for test.str is the address of another block of memory. 请注意,对于数据test.arr存储分配内存test ,而是存储在事test对于test.str是另一个内存块的地址。

You have to give the compiler information about the type of pointer you have in functions f and g , you can't do point arithmetic on void pointers. 你必须给编译器提供有关函数fg中指针类型的信息,你不能对void指针进行点运算。

Cast data to a char pointer and the printf's will work 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);
}

In function f , what is (data + offset) actually pointing at? 在函数f ,实际指向的是什么(data + offset) Is it not pointing to arr which is a char pointer to the first element of the string? 是不是指向arr哪个是指向字符串第一个元素的char指针?

This is your primary source of confusion. 这是您混淆的主要原因。 arr is not a pointer, it is an array. arr不是指针,它是一个数组。 Arrays are not pointers. 数组不是指针。 Meanwhile, str is a pointer. 同时, str是一个指针。 "Arrays" and "pointers" are two absolutely different things. “数组”和“指针”是两个完全不同的东西。 They have virtually nothing in common. 他们几乎没有任何共同之处。 And this is exactly why you have to work with them differently. 这正是您必须以不同方式使用它们的原因。

Arrays and pointers can behave very similarly in so called value contexts (ie when used as rvalues ), but this is purely superficial similarity. 在所谓的值上下文中 (即当用作rvalues时 ),数组和指针的行为非常相似,但这纯粹是肤浅的相似性。 They immediately reveal their major differences in so called object contexts (ie when used as lvalues ). 他们立即揭示了他们在所谓的对象上下文中的主要差异(即当用作左值时 )。 In your specific example your member-accessing code is an example of object context , which is why you have to carefully observe the difference between arr and str . 在您的特定示例中,您的成员访问代码是对象上下文的示例,这就是您必须仔细观察arrstr之间差异的原因。

The matter of differences between arrays and pointers has been covered many times already. 数组和指针之间的差异问题已经涵盖了很多次。 I don't see any reason to repeat it here. 我认为没有理由在此重复。 Just do a search on "array pointer difference" on SO. 只需在SO上搜索“数组指针差异”即可。 Or read the essential FAQ 或者阅读必要的FAQ

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

PS Also note that C language does not support pointer arithmetic on void * pointers. PS还要注意C语言不支持void *指针上的指针算法。 All of your your (data + offset) expressions are invalid. 您的所有(data + offset)表达式都无效。 What you wanted to do is really ((char *) data + offset) . 你想要做的是((char *) data + offset) The conversion of data from void * to char * is required in order to be able to perform point arithmetic with byte-offsets. 为了能够使用字节偏移执行点算术,需要将datavoid *转换为char *

In your struct, at (presumably) offset 4, is a list of 10 bytes one after each other, containing the letters that make 'Hello'; 在你的结构中,在(推测)偏移4处,是一个一个接一个的10个字节的列表,包含制作'Hello'的字母; So (data+4) is a pointer at char and needs to be dcoded accordingly (ie char * ). 所以(data + 4)是char的指针,需要相应地进行dcoded(即char * )。

However, after those 10 bytes, come a few bytes that make the address of a buffer somewhere, ie those bytes are a 'char *' (you defined them so), so data+offset there is a pointer at a char-pointer or a char ** . 然而,在那10个字节之后,来一些字节使缓冲区的地址在某处,即那些字节是'char *'(你定义它们),所以数据+偏移有一个指针在char指针或一个char **

What is probably confusing is that both 可能令人困惑的是两者兼而有之

strcpy(test.arr, "Hello "); strcpy(test.arr,“你好”);
strcpy(test.str, "World!"); strcpy(test.str,“World!”);

work. 工作。

This is a confusing (but useful feature of C/C++). 这是一个令人困惑的(但很有用的C / C ++特性)。 The name of an array, when used in a place that requires a pointer to the type of the array element, will be treated by the compiler as if it were a pointer to the first element of the array. 当数组的名称在需要指向数组元素类型的指针的位置中使用时,编译器将对其进行处理,就像它是指向数组的第一个元素的指针一样。

So test.str is clearly a pointer to char (because you defined it that way). 所以test.str显然是一个指向char的指针(因为你这样定义)。 test.arr can be used as a pointer to the first element of test, if the situation suggests it. 如果情况表明, test.arr 可以用作指向第一个测试元素的指针。

When you write strcpy(test.arr, "Hello "); 当你写strcpy(test.arr, "Hello "); what the compiler assumes you mean is strcpy(&test.arr[0], "Hello "); 编译器假设你的意思是strcpy(&test.arr[0], "Hello ");

In function f, what is (data + offset) actually pointing at? 在函数f中,实际指向的是什么(数据+偏移量)?

It is pointing at the 'arr' member of the structure object (if you assume GCC's semantics for the void pointer arithmetic). 它指向结构对象的'arr'成员(如果你假设GCC的void指针算术的语义)。

Is it not pointing to arr which is a char pointer to the first element of the string? 是不是指向arr哪个是指向字符串第一个元素的char指针?

arr is a char array, not a char pointer. arr是一个char数组,而不是char指针。

But in function g, (data + offset) is pointing to a char pointer too. 但是在函数g中,(data + offset)也指向了char指针。

In this case, it is pointing to a char pointer, yes. 在这种情况下,它指向一个char指针,是的。

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. 指针指向两个不同的东西 - 一个指向char指针(它本身指向一个char数组),另一个指向char数组。 There is one more level of indirection in the first case. 在第一种情况下还有一个间接级别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM