从结构数组传递一个元素并在 C 中连接一个字符串

Pass an element from a structs array and concatenate a string in C

我有一个结构数组,其中包含具有以下定义的结构:

typedef struct
{
    void *data;
    void (*print)(void *);
    status_ty (*add)(void *, int);
    void (*free_element)(void *);
} element_ty;

每个元素可以是“int”元素、“float”元素或“string”元素。

我希望能够 add int 每个元素的值。

例如:

add (3, array, size_of_array);

将遍历数组并将 3 的值添加到每个元素中。

Add 总是添加一个 int 值,对于 int 和 float 元素,这是正常的添加,对于字符串,它应该进行连接。

例如:

我的问题是:

这是 AddToStr 函数的伪代码:

我很困惑。

这是我到目前为止写的:

    void FreeStrElement(void *(element_ty *element))
{

    free(element -> data);  

}


/*------------------------------------------------------------------*/

    void AddToInt(void *(element_ty *element), int IncrementValue)
{

    int data = (int) element -> data;
    int sum = data + IncrementValue;
    element -> data = (void *) sum; 

}

/*------------------------------------------------------------------*/

void AddToFlt(void *(element_ty *element), int IncrementValue)
{

    float data = (float *) element -> data;
    float sum = data + IncrementValue;
    element -> data = (void *) *(float *)∑
}

/*------------------------------------------------------------------*/

void AddToStr(void *(element_ty *element), int IncrementValue)
{

    ??

}


/*------------------------------------------------------------------*/

void PrintStr(void *num)
{

    printf("String in the element: %s\n", (char **) &num);  

}


/*------------------------------------------------------------------*/

status_ty InitStr(const char *value, element_ty *element)
{
    element -> data = (void *)value;
    element -> print = PrintStr;
    element -> add = AddtoStr;
    element -> free_element = FreeStrElement;
    
}

分配给每个元素的函数需要将 element* 作为输入,因为它们需要能够根据需要修改 data 成员。这对于“字符串”元素尤其重要,因为您需要能够在添加更多字符时重新分配字符串内存,这意味着将新的 char* 指针分配给 data.

您可以将 element* 指针作为 void* 参数传递(您说这是必需的),但您必须将 void* 类型转换回 element* 在函数体中

尝试这样的事情:

typedef struct
{
    void *data;
    void (*print)(void *);
    status_ty (*add)(void *, int);
    void (*free_element)(void *);
} element_ty;

/*------------------------------------------------------------------*/

void FreeStrElement(void *element)
{
    element_ty *p_element = (element_ty *) element;
    free(p_element->data);
}

/*------------------------------------------------------------------*/

status_ty AddToInt(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    int *p_value = (int*) &(p_element->data);
    *p_value += IncrementValue;
    return ...;
}

/*------------------------------------------------------------------*/

status_ty AddToFlt(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    float *p_value = (float*) &(p_element->data);
    *p_value += IncrementValue;
    return ...;
}

/*------------------------------------------------------------------*/

status_ty AddToStr(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    char *p_str = (char*) p_element->data;

    char *new_str = realloc(p_str, strlen(p_str) + 13);
    if (!new_str) return ...;

    sprintf(new_str, "%s%d", p_str, IncrementValue);

    p_element->data = new_str;

    return ...;
}

/*------------------------------------------------------------------*/

void PrintInt(void *element)
{
    element_ty *p_element = (element_ty *) element;
    int *p_value = (int*) &(p_element->data);
    printf("Integer in the element: %d\n", *p_value);
}

/*------------------------------------------------------------------*/

void PrintFlt(void *element)
{
    element_ty *p_element = (element_ty *) element;
    float *p_value = (float*) &(p_element->data);
    printf("Float in the element: %f\n", *p_value);
}

/*------------------------------------------------------------------*/

void PrintStr(void *element)
{
    element_ty *p_element = (element_ty *) element;
    char *p_str = (char*) p_element->data;
    printf("String in the element: %s\n", p_str);
}

/*------------------------------------------------------------------*/

status_ty InitInt(int value, element_ty *element)
{
    int *p_value = (int*) &(element->data);
    *p_value = value;
    element->print = &PrintInt;
    element->add = &AddToInt;
    element->free_element = NULL;

    return ...;
}

/*------------------------------------------------------------------*/

status_ty InitFlt(float value, element_ty *element)
{
    float *p_value = (float*) &(element->data);
    *p_value = value;
    element->print = &PrintFlt;
    element->add = &AddToFlt;
    element->free_element = NULL;

    return ...;
}

/*------------------------------------------------------------------*/

status_ty InitStr(const char *value, element_ty *element)
{
    element->data = strdup(value);
    element->print = &PrintStr;
    element->add = &AddToStr;
    element->free_element = &FreeStrElement;

    return ...;
}

/*------------------------------------------------------------------*/

那么你可以这样做:

void add (int value, element_ty *elements, int n) {
    for(int i = 0 i < n; ++i) {
        element_ty *elem = &elements[i];
        elem->add(elem, value);
    }
}

void print (element_ty *elements, int n) {
    for(int i = 0 i < n; ++i) {
        element_ty *elem = &elements[i];
        elem->print(elem);
    }
}

void free_elements (element_ty *elements, int n) {
    for(int i = 0 i < n; ++i) {
        element_ty *elem = &elements[i];
        if (elem->free_element) elem->free_element(elem);
    }
}

也就是说,这种方法假设 sizeof(int)sizeof(float) <= sizeof(void*)通常 是这种情况,但不是保证。

这种方法也违反了严格的别名规则。您可以使用 memcpy() 来避免这种情况,但是使用 union 会更容易和更清晰(它也避免了 sizeof 问题),例如:

typedef struct
{
    union {
        int i;
        float f;
        char *s;
    } data;
    void (*print)(void *);
    status_ty (*add)(void *, int);
    void (*free_element)(void *);
} element_ty;

/*------------------------------------------------------------------*/

void FreeStrElement(void *element)
{
    element_ty *p_element = (element_ty *) element;
    free(p_element->data.s);
}

/*------------------------------------------------------------------*/

status_ty AddToInt(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    p_element->data.i += IncrementValue;
    return ...;
}

/*------------------------------------------------------------------*/

status_ty AddToFlt(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    p_element->data.f += IncrementValue;
    return ...;
}

/*------------------------------------------------------------------*/

status_ty AddToStr(void *element, int IncrementValue)
{
    element_ty *p_element = (element_ty *) element;
    char *p_str = p_element->data.s;

    char *new_str = realloc(p_str, strlen(p_str) + 13);
    if (!new_str) return ...;

    sprintf(new_str, "%s%d", p_str, IncrementValue);

    p_element->data.s = new_str;

    return ...;
}

/*------------------------------------------------------------------*/

void PrintInt(void *element)
{
    element_ty *p_element = (element_ty *) element;
    printf("Integer in the element: %d\n", p_element->data.i);
}

/*------------------------------------------------------------------*/

void PrintFlt(void *element)
{
    element_ty *p_element = (element_ty *) element;
    printf("Float in the element: %f\n", p_element->data.f);
}

/*------------------------------------------------------------------*/

void PrintStr(void *element)
{
    element_ty *p_element = (element_ty *) element;
    printf("String in the element: %s\n", p_element->data.s);
}

/*------------------------------------------------------------------*/

status_ty InitInt(int value, element_ty *element)
{
    element->data.i = value;
    element->print = &PrintInt;
    element->add = &AddToInt;
    element->free_element = NULL;

    return ...;
}

/*------------------------------------------------------------------*/

status_ty InitFlt(float value, element_ty *element)
{
    element->data.f = value;
    element->print = &PrintFlt;
    element->add = &AddToFlt;
    element->free_element = NULL;

    return ...;
}

/*------------------------------------------------------------------*/

status_ty InitStr(const char *value, element_ty *element)
{
    element->data.s = strdup(value);
    element->print = &PrintStr;
    element->add = &AddToStr;
    element->free_element = &FreeStrElement;

    return ...;
}

/*------------------------------------------------------------------*/