[英]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;
}
我想知道为什么我需要两种不同的方式来打印字符串。 在函数f中 ,实际指向的是什么(数据+偏移量)? 是不是指向arr哪个是指向字符串第一个元素的char指针? 但是在函数g中 ,(data + offset)也指向了char指针。 那么为什么必须使用两种不同的方法来完成同样的任务呢?
在这两种情况下, 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
,而是存储在事test
对于test.str
是另一个内存块的地址。
你必须给编译器提供有关函数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);
}
在函数
f
,实际指向的是什么(data + offset)
? 是不是指向arr
哪个是指向字符串第一个元素的char指针?
这是您混淆的主要原因。 arr
不是指针,它是一个数组。 数组不是指针。 同时, str
是一个指针。 “数组”和“指针”是两个完全不同的东西。 他们几乎没有任何共同之处。 这正是您必须以不同方式使用它们的原因。
在所谓的值上下文中 (即当用作rvalues时 ),数组和指针的行为非常相似,但这纯粹是肤浅的相似性。 他们立即揭示了他们在所谓的对象上下文中的主要差异(即当用作左值时 )。 在您的特定示例中,您的成员访问代码是对象上下文的示例,这就是您必须仔细观察arr
和str
之间差异的原因。
数组和指针之间的差异问题已经涵盖了很多次。 我认为没有理由在此重复。 只需在SO上搜索“数组指针差异”即可。 或者阅读必要的FAQ
http://c-faq.com/aryptr/index.html
PS还要注意C语言不支持void *
指针上的指针算法。 您的所有(data + offset)
表达式都无效。 你想要做的是((char *) data + offset)
。 为了能够使用字节偏移执行点算术,需要将data
从void *
转换为char *
。
在你的结构中,在(推测)偏移4处,是一个一个接一个的10个字节的列表,包含制作'Hello'的字母; 所以(data + 4)是char的指针,需要相应地进行dcoded(即char *
)。
然而,在那10个字节之后,来一些字节使缓冲区的地址在某处,即那些字节是'char *'(你定义它们),所以数据+偏移有一个指针在char指针或一个char **
。
可能令人困惑的是两者兼而有之
strcpy(test.arr,“你好”);
strcpy(test.str,“World!”);
工作。
这是一个令人困惑的(但很有用的C / C ++特性)。 当数组的名称在需要指向数组元素类型的指针的位置中使用时,编译器将对其进行处理,就像它是指向数组的第一个元素的指针一样。
所以test.str
显然是一个指向char的指针(因为你这样定义)。 如果情况表明, test.arr
可以用作指向第一个测试元素的指针。
当你写strcpy(test.arr, "Hello ");
编译器假设你的意思是strcpy(&test.arr[0], "Hello ");
在函数f中,实际指向的是什么(数据+偏移量)?
它指向结构对象的'arr'成员(如果你假设GCC的void指针算术的语义)。
是不是指向arr哪个是指向字符串第一个元素的char指针?
arr是一个char数组,而不是char指针。
但是在函数g中,(data + offset)也指向了char指针。
在这种情况下,它指向一个char指针,是的。
那么为什么必须使用两种不同的方法来完成同样的任务呢?
指针指向两个不同的东西 - 一个指向char指针(它本身指向一个char数组),另一个指向char数组。 在第一种情况下还有一个间接级别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.