在堆上创建结构?

时间:2009-10-26 04:10:53

标签: c heap

我已经被指示通过在堆上创建一个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;
}   

4 个答案:

答案 0 :(得分:8)

是的,你已经在堆上创建了一个结构。你没有正确填充它,你将面临删除它的问题 - 我不确定作业是否涵盖了。就目前而言,你更容易出现内存损坏,或者,如果幸运的话,内存泄漏,而不是释放其中一个字符串。

适用于标准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编译器)。断言是次优的错误处理。代码不会针对输入的空指针进行自我防御。在这种情况下,长度和容量都不会带来任何好处 - 套件中必须有其他功能才能使用该信息。

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


仅适用于标准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;'进行强制转换。告诉编译器我的意思是我所说的;我现在已经解决了这个问题并留下了评论以显示原文。


使用'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;
}

使用C89和C99

的GCC非标准扩展的代码

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)

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

答案 3 :(得分:0)

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