我已经被指示通过在堆上创建一个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;
}
答案 0 :(得分: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。 (或 - &gt;) operator有一个左操作数,它是一个带有灵活数组成员的结构(指向) 并且右边的操作数命名该成员,它的行为就像该成员被替换一样 最长的数组(具有相同的元素类型),不会构成结构 大于被访问的对象;数组的偏移量应保持为 灵活的阵列成员,即使这与替换阵列的成员不同。如果这 数组没有元素,它的行为好像它有一个元素,但行为是 如果尝试访问该元素或生成过去的指针,则为undefined 它
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 <assert.h>
#include <stdlib.h>
#include <string.h>
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很难学习而不需要学习一些特定于编译器的特技。
答案 1 :(得分:2)
您已经在堆上分配了一些内存,但是您没有使用它,就好像它是您的结构一样。函数中的string
变量属于char *
类型,而不是类型struct String
。我认为你正在合理地复制strdup()
的功能,但我不明白结构的原因。
注意:您应该检查对malloc()
的调用是否失败,并适当返回。 strdup()
的手册页应该准确解释您的功能应该做什么。
答案 2 :(得分:0)
答案 3 :(得分:0)
是的,malloc
返回堆上的内存。