在堆上创建结构?

我已经被指示通过在堆上创建一个String结构来编写模型strdup,它包含源的副本。 我想我已成功编写了strdup,但我不确定我是否在堆上创建了一个Struct

typedef struct String { int length; int capacity; unsigned check; char ptr[0]; } String; char* modelstrdup(char* src){ int capacity =0, length=0, i = 0 ; char *string; while ( src[length] != '\0'){ length++; } capacity = length; string = malloc(sizeof(String) + capacity + 1); while ( i < length ){ string[i] = src[i]; i++; } string[i+1] = '\0'; return string; } 

是的,您已在堆上创建了一个结构。 你没有正确填充它,你将面临删除它的问题 – 我不确定这项功课是否涵盖了。 就目前而言,你更有可能获得内存损坏,或者,如果幸运的话,内存泄漏,而不是释放其中一个字符串。

适用于标准C89和C99的代码

你的代码,有点固定……

 typedef struct String { int length; int capacity; char *ptr; } String; char* modelstrdup(char* src){ int length = strlen(src); char *space = malloc(sizeof(String) + length + 1); //String *string = space; // Original code - compilers are not keen on it String *string = (String *)space; assert(space != 0); string->ptr = space + sizeof(String); // or sizeof(*string) string->length = length; string->capacity = length + 1; strcpy(string->ptr, src); return string->ptr; } 

此代码适用于C89和C99(C99 / C ++注释除外)。 您可以优化它以使用’struct hack’(在结构中保存指针 – 但前提是您有C99编译器)。 断言是次优的error handling。 代码不会针对输入的空指针进行自我防御。 在这种情况下,长度和容量都不会带来任何好处 – 套件中必须有其他function才能使用该信息。

正如已经暗示的那样,当回传的值不是指向字符串的指针时,您将面临删除字符串结构的问题。 你有一些微妙的指针调整。


仅适用于标准C99的代码

在C99中,第6.7.2.1节第16段描述了“灵活的arrays成员”:

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活的arrays成员。 除了两个例外,灵活的数组成员将被忽略。 首先,结构的大小应等于其他相同结构的最后一个元素的偏移量,该结构用一个未指定长度的数组替换柔性arrays成员。 106)第二,当a。 (或 – >)运算符有一个左操作数,它是一个带有灵活数组成员的结构(指针),右操作数命名该成员,它的行为就好像该成员被最长的数组替换(具有相同的元素类型) )不会使结构大于被访问的对象; 数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同。 如果此数组没有元素,则其行为就好像它有一个元素,但如果任何尝试访问该元素或生成一个经过它的指针,则行为是未定义的。

106长度未指定,以允许实现可以根据数组成员的长度为数组成员提供不同的对齐。

使用“灵活的arrays成员”,您的代码可能变为:

 typedef struct String { int length; int capacity; char ptr[]; } String; char* modelstrdup(char* src){ int length = strlen(src); String *string = malloc(sizeof(String) + length + 1); assert(string != 0); string->length = length; string->capacity = length + 1; strcpy(string->ptr, src); return string->ptr; } 

除了函数声明(options -Wall -Wextra )之外,GCC 4.0.1接受了此代码的清除。 前面的代码需要对’String * string =(String *)space;’进行强制转换。 告诉编译器我的意思是我所说的; 我现在已经解决了这个问题并留下了评论以显示原文。


使用’struct hack’

在C99之前,人们经常使用’struct hack’来处理这个问题。 它与问题中显示的代码非常相似,除了数组的维数为1,而不是0.标准C不允许大小为零的数组维度。

 typedef struct String { size_t length; size_t capacity; char ptr[1]; } String; char* modelstrdup(char* src) { size_t length = strlen(src); String *string = malloc(sizeof(String) + length + 1); assert(string != 0); string->length = length; string->capacity = length + 1; strcpy(string->ptr, src); return string->ptr; } 

使用GCC非标准扩展到C89和C99的代码

GCC接受零大小的数组符号,除非你用力戳 – 指定ISO C标准并请求迂腐准确性。 因此,除非您使用gcc -Wall -Wextra -std=c99 -pedantic ,否则此代码编译正常:

 #include  #include  #include  typedef struct String { int length; int capacity; char ptr[0]; } String; char* modelstrdup(char* src){ int length = strlen(src); String *string = malloc(sizeof(String) + length + 1); assert(string != 0); string->length = length; string->capacity = length + 1; strcpy(string->ptr, src); return string->ptr; } 

但是,在彻底掌握标准C的基础知识之前,不应该接受C语言的非标准扩展培训。这对您来说是不公平的; 你不知道你被告知要做什么是明智的,但你的导师不应该强迫你使用非标准的东西来误导你。 即使他们提醒你这是非标准的事实,这对你来说也不公平。 C很难学习,而不需要学习特定于编译器的特技。

你已经在堆上分配了一些内存,但是你没有像使用它那样使用它。 函数中的string变量是char *类型,而不是struct String类型。 我认为你正在合理地复制strdup()的function,但我不明白结构的原因。

注意:您应该检查对malloc()调用是否失败,并适当地返回。 strdup()的手册页应该准确解释你的函数应该做什么。

你有。 malloc,new等都使用堆。

是的, malloc返回堆上的内存。