从结构数组传递一个元素并在 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 元素,这是正常的添加,对于字符串,它应该进行连接。
例如:
- 如果数组包含以下元素:4.2, 6, "welcome" - 那么如果将 3 添加到每个元素,结果将是:7.2, 9, "welcome3"
我的问题是:
- 当
add
得到一个 void *
并且我传递的指针类型为 element_ty
时,我应该如何将元素本身传递给 add
函数(结构), 这将指向数组中的这个特定元素?
看下面我写的代码,如果有错误请告诉我
这是 AddToStr
函数的伪代码:
- 收到应该添加的
int
值
- 将位于
element -> data
中的现有 string
转换为 string
(?) 以便稍后连接它?当前 data
存储为 void *
. 类型
malloc
字符串能接收int
值吗?
- 再次将其转换为
void *
并将其存储在 element -> data
?
free()
malloc
?
我很困惑。
这是我到目前为止写的:
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 ...;
}
/*------------------------------------------------------------------*/
我有一个结构数组,其中包含具有以下定义的结构:
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 元素,这是正常的添加,对于字符串,它应该进行连接。
例如:
- 如果数组包含以下元素:4.2, 6, "welcome" - 那么如果将 3 添加到每个元素,结果将是:7.2, 9, "welcome3"
我的问题是:
- 当
add
得到一个void *
并且我传递的指针类型为element_ty
时,我应该如何将元素本身传递给add
函数(结构), 这将指向数组中的这个特定元素? 看下面我写的代码,如果有错误请告诉我
这是 AddToStr
函数的伪代码:
- 收到应该添加的
int
值 - 将位于
element -> data
中的现有string
转换为string
(?) 以便稍后连接它?当前data
存储为void *
. 类型
malloc
字符串能接收int
值吗?- 再次将其转换为
void *
并将其存储在element -> data
? free()
malloc
?
我很困惑。
这是我到目前为止写的:
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 ...;
}
/*------------------------------------------------------------------*/