在堆上创建结构体?

2023-12-04

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

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 编译器)。断言是次优错误处理。该代码不会防御输入的空指针。在这种情况下,长度和容量都没有提供任何好处 - 套件中必须有其他功能能够利用该信息。

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


仅适用于标准 C99 的代码

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

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. With two exceptions, the flexible array member is ignored. First, the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length.106) Second, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.

106 The length is unspecified to allow for the fact that implementations may give array members different alignments according to their lengths.

使用“灵活数组成员”,您的代码可能会变成:

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)。前面的代码需要对“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;
}

使用 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 就很难学了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在堆上创建结构体? 的相关文章

随机推荐