我已经被指示通过在堆上创建一个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; }
Jonathan Lef.. 8
是的,你已经在堆上创建了一个结构.你没有正确填充它,你将面临删除它的问题 - 我不确定作业是否涵盖了.就目前而言,你更有可能得到内存损坏,或者,如果幸运的话,内存泄漏,而不是释放其中一个字符串.
你的代码有点固定......
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编译器时).断言是次优的错误处理.代码不会针对输入的空指针进行自我防御.在这种情况下,长度和容量都不会带来任何好处 - 套件中必须有其他功能才能使用该信息.
正如已经暗示的那样,当回传的值不是指向字符串的指针时,您将面临删除字符串结构的问题.你有一些微妙的指针调整.
在C99中,第6.7.2.1节第16段描述了"灵活的阵列成员":
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这被称为灵活的阵列成员.除了两个例外,灵活的数组成员将被忽略.首先,结构的大小应等于其他相同结构的最后一个元素的偏移量,该结构用一个未指定长度的数组替换柔性阵列成员.106)第二,当a.(或 - >)运算符有一个左操作数,它是一个带有灵活数组成员的结构(一个指针),右操作数命名该成员,它的行为就好像该成员被最长的数组替换(具有相同的元素类型) )不会使结构大于被访问的对象; 数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同.如果此数组没有元素,则其行为就好像它有一个元素,但如果尝试访问该元素或生成一个超过它的指针,则行为是未定义的.
106长度未指定,以允许实现可以根据数组成员的长度为数组成员提供不同的对齐.
使用"灵活的阵列成员",您的代码可能变为:
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; }
除了函数声明(选项-Wall -Wextra
)之外,此代码被GCC 4.0.1接受为清除.前面的代码需要对'String*string =(String*)space;'进行强制转换.告诉编译器我的意思是我所说的; 我现在已经解决了这个问题并留下了评论以显示原文.
在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接受零大小的数组符号,除非你用力戳 - 指定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很难学习,而不需要学习特定于编译器的特技.
是的,你已经在堆上创建了一个结构.你没有正确填充它,你将面临删除它的问题 - 我不确定作业是否涵盖了.就目前而言,你更有可能得到内存损坏,或者,如果幸运的话,内存泄漏,而不是释放其中一个字符串.
你的代码有点固定......
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编译器时).断言是次优的错误处理.代码不会针对输入的空指针进行自我防御.在这种情况下,长度和容量都不会带来任何好处 - 套件中必须有其他功能才能使用该信息.
正如已经暗示的那样,当回传的值不是指向字符串的指针时,您将面临删除字符串结构的问题.你有一些微妙的指针调整.
在C99中,第6.7.2.1节第16段描述了"灵活的阵列成员":
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这被称为灵活的阵列成员.除了两个例外,灵活的数组成员将被忽略.首先,结构的大小应等于其他相同结构的最后一个元素的偏移量,该结构用一个未指定长度的数组替换柔性阵列成员.106)第二,当a.(或 - >)运算符有一个左操作数,它是一个带有灵活数组成员的结构(一个指针),右操作数命名该成员,它的行为就好像该成员被最长的数组替换(具有相同的元素类型) )不会使结构大于被访问的对象; 数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同.如果此数组没有元素,则其行为就好像它有一个元素,但如果尝试访问该元素或生成一个超过它的指针,则行为是未定义的.
106长度未指定,以允许实现可以根据数组成员的长度为数组成员提供不同的对齐.
使用"灵活的阵列成员",您的代码可能变为:
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; }
除了函数声明(选项-Wall -Wextra
)之外,此代码被GCC 4.0.1接受为清除.前面的代码需要对'String*string =(String*)space;'进行强制转换.告诉编译器我的意思是我所说的; 我现在已经解决了这个问题并留下了评论以显示原文.
在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接受零大小的数组符号,除非你用力戳 - 指定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很难学习,而不需要学习特定于编译器的特技.