作为练习,我使用函数指针在C中实现字符串“class”。
这是我定义结构的开始。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct SString* String;
struct SString
{
char* (*get)(const void* self);
void (*set)(const void* self, char* value);
int (*length)(const void* self);
void (*destroy)(void* self);
char* str;
int isInit;
};
这是我感兴趣的“方法”:
void setString(const void* self, char* value)
{
/* Allocate an extra char for the null terminator, otherwise heap corruption happens */
/* If string is not init, realloc works with NULL and acts like malloc */
/* Once it is init, it will work on the pointer like realloc */
((String)self)->str = (char*)realloc( ((!((String)self)->isInit) ? NULL : ((String)self)->str) , (sizeof(char) * strlen(value))+1 );
strcpy(((String)self)->str,value);
}
void destroyString(void* self)
{
free(((String)self)->str);
free(self);
}
String newString(char* value)
{
String self = (String)malloc(sizeof(struct SString));
self->get = &getString;
self->set = &setString;
self->length = &lengthString;
self->destroy = &destroyString;
self->isInit = 0; /* Malloc str for the first time */
self->set(self,value);
self->isInit = 1; /* Subsequent set() will realloc from now on */
return self;
}
我的主要是测试这些东西:
int main(void)
{
String s = newString("Original init string");
printf("%s\nIt is %d chars long.\n\n",s->get(s),s->length(s));
s->set(s,"This is a test of a pseudo string class");
printf("%s\nIt is %d chars long.\n\n",s->get(s),s->length(s));
s->destroy(s);
s = newString("Hello");
printf("%s\nIt is %d chars long.\n\n",s->get(s),s->length(s));
s->set(s,"Resetting the string once again and then deleting");
puts(s->get(s));
s->destroy(s);
return 0;
}
从表面上看,一切正常,我得到了预期的输出。 但是,我觉得我正在使用setString()函数做一些hackery,它会切换realloc()的行为方式。 当我调用我的destroyString()函数并释放结构中的self“instance”和str时,我很确定下次调用newString()时,它会重置所有内容,因此realloc正在处理一个新的指针,旧的已被释放。因此理论上不应该有任何内存泄漏。
我只使用单一设置函数进行初始化和后续设置,因为我觉得这是一个更优雅的解决方案,而不是具有多个函数用于初始化和后续集合,但是权衡结束了我的一些realloc()hackery,我我不太确定它是完全合理的。