结构中的字符数组 - 不兼容的分配? [复制]
Posted
技术标签:
【中文标题】结构中的字符数组 - 不兼容的分配? [复制]【英文标题】:Char array in a struct - incompatible assignment? [duplicate] 【发布时间】:2010-11-20 12:36:36 【问题描述】:我试图找出一个结构到底是什么并遇到了一个问题,所以我真的有两个问题:
1) 'sara' 中保存了什么?它是指向结构的第一个元素的指针吗?
2) 更有趣的问题:为什么不编译? GCC 说“test.c:10: error: incompatible types in assignment”,我不知道为什么...... (这部分已经被你的回答解决了,太好了!)
#include <stdio.h>
struct name
char first[20];
char last[20];
;
int main()
struct name sara;
sara.first = "Sara";
sara.last = "Black";
printf("struct direct: %x\n",sara);
printf("struct deref: %x\t%s\n", *sara, *sara);
感谢您的帮助!
【问题讨论】:
哇。但我确实搜索过:D 【参考方案1】:这与结构无关 - C 中的数组不可赋值:
char a[20];
a = "foo"; // error
你需要使用strcpy:
strcpy( a, "foo" );
或在您的代码中:
strcpy( sara.first, "Sara" );
【讨论】:
+1 对于strcpy
超过strncpy
... :)
我会先使用 char*; sara.first = "Sara",因为我只在真正需要时才使用固定大小的数组;这是一个好习惯还是坏习惯(在 C 中,而不是 C++ 中)?
@gramm 如果你这样做,你就是在致力于动态内存管理,这可能不是必需的或不可取的。
@gramm 在很多情况下,数组表现得更好。使用char *
,sara.first="Sara"; sara.first[0]='s';
会死得很惨,因为字符串"Sara"
在只读内存中。
@GManNickG 你能否详细说明为什么strncpy
不好?【参考方案2】:
或者你可以只使用动态分配,例如:
struct name
char *first;
char *last;
;
struct name sara;
sara.first = "Sara";
sara.last = "Black";
printf("first: %s, last: %s\n", sara.first, sara.last);
【讨论】:
这不是动态分配。字符串“Sara”和“Black”是在编译时创建的,您只需在运行时将结构成员指向这些字符串。【参考方案3】:你也可以这样初始化:
struct name sara = "Sara", "Black" ;
因为(作为一种特殊情况)您可以从字符串常量初始化字符数组。
现在,至于结构实际上是什么 - 它是由其他值组成的复合类型。 sara
在内存中实际上看起来是一个 20 个连续 char 值的块(可以使用 sara.first
引用,后跟 0 个或多个填充字节,然后是另一个 20 个连续 char 值的块(可以引用使用sara.last
)。struct name
类型的所有其他实例都以相同的方式布局。
在这种情况下,几乎不可能有任何填充,因此struct name
只是一个由 40 个字符组成的块,您可以为其命名为前 20 个和后 20 个字符。
您可以使用sizeof(struct name)
找出struct name
占用的内存块有多大,并且您可以使用offsetof(struct name, first)
和offsetof(struct name, last)
找出该结构的每个成员在该内存块中的位置.
【讨论】:
【参考方案4】:使用strncpy
确保没有缓冲区溢出。
char name[]= "whatever_you_want";
strncpy( sara.first, name, sizeof(sara.first)-1 );
sara.first[sizeof(sara.first)-1] = 0;
【讨论】:
这假设静默截断数据不会导致您的程序在其他地方失败。显式处理字符串不适合缓冲区的情况通常比使用 strcpy 调用未定义行为或使用 strncpy 将程序置于意外状态更好。但我概括一下 - 如果您的程序的其余部分考虑了静默截断(例如,从不期望 sara.first 将匹配“whatever_you_want”),那么程序状态并不意外。 @onebyone 这种行为必须记录在合同中。 如果这已经足够了,那么为什么不直接记录输入字符串不能超过结构可以处理的长度呢?问题是设计帮助客户避免错误的 API 之一。 IMO,默默地忽略可能是错误的东西并没有这样做。但正如我所说,我是在概括,这可能不是一个错误。如果该函数被称为“StoreFirst20CharsOf”,那么我们可以合理地假设任何查看调用代码的人都会理解它的作用。所以 strncpy 有一些用途。 StoreFirst20CharsOf 绝对是这样做的方式...... @SteveJessop:简单地记录输入字符串不能超过特定长度会导致缓冲区溢出。恕我直言,最好记录 API 将截断超过 20 个字符的名称,并且不要引入缓冲区溢出漏洞。并且截断不必是无声的;如果调用者关心,API 可以向调用者发出截断发生的信号。虽然截断可能有时会导致错误,但缓冲区溢出总是是错误(并且是最糟糕的错误之一)。【参考方案5】:sara
是结构本身,而不是指针(即表示存储实际结构数据的堆栈位置的变量)。因此,*sara
没有意义,不会编译。
【讨论】:
【参考方案6】:您可以使用 strcpy 来填充它。你也可以从另一个结构初始化它。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct name
char first[20];
char last[20];
;
int main()
struct name sara;
struct name other;
strcpy(sara.first,"Sara");
strcpy(sara.last, "Black");
other = sara;
printf("struct: %s\t%s\n", sara.first, sara.last);
printf("other struct: %s\t%s\n", other.first, other.last);
【讨论】:
【参考方案7】:Sara 结构是一个包含变量的内存块。经典声明几乎没有区别:
char first[20];
int age;
还有一个结构:
struct Person
char first[20];
int age;
;
在这两种情况下,您只是分配一些内存来存储变量,并且在这两种情况下都会保留 20+4 个字节。在您的情况下,Sara 只是一个 2x20 字节的内存块。
唯一的区别是,对于一个结构,内存是作为一个单独的块分配的,所以如果你取 Sara 的起始地址并跳转 20 个字节,你会找到“last”变量。这有时很有用。
查看http://publications.gbdirect.co.uk/c_book/chapter6/structures.html 了解更多信息:)。
【讨论】:
Sara 是一个至少 2 * 20 字节的内存块。如果有填充,它可能会更多。 而且offsetof(struct name, last)
也不一定是 20(尽管几乎可以肯定是)。
不知道。指定可变大小时是否有填充的可能性?例如,无符号字符速度:7;无符号字符标志:3;等等......我在工作中使用它并且从来没有遇到过填充和数据对齐的问题。
如果位域跟在一个非位域成员之后,那么可以有 before 的填充。不允许在 两个相邻位域之间填充,除非它们不适合用于保存它们的相同“基本存储单元”(例如,如果您的实现使用 8 位chars 来保存位域,那么它可能会为flags
开始一个全新的字符,而在保存speed
的字符中留下一个未使用的位)。在底层类型中,位域是从左到右还是从右到左分配也是左定义的。
从技术上讲,第二个还没有分配任何东西。它只是说“如果你稍后看到Person
类型的数据,它的布局是这样的”【参考方案8】:
你可以这样试试。我在我的案例中应用了这个。
#include<stdio.h>
struct name
char first[20];
char last[30];
;
//globally
// struct name sara="Sara","Black";
int main()
//locally
struct name sara="Sara","Black";
printf("%s",sara.first);
printf("%s",sara.last);
【讨论】:
以上是关于结构中的字符数组 - 不兼容的分配? [复制]的主要内容,如果未能解决你的问题,请参考以下文章