我正在尝试为我正在制作的包装器做一些有用的事情。我正在为C编写标准字符串库的包装器,因为我不喜欢它。
我现在不想将C字符串引入我的包装器。我有一个名为`str的结构,它包含字符串的长度和缓冲区:
struct str
{
char *buf;
size_t len;
};
在我的标题文件中,我有这个:
typedef struct str str;
现在我已经实现了封装(我认为)。
所以我声明这样的字符串:
str *a_string = NULL;
我已经完成了我想做的所有事情,但我有一个问题。我想为一个函数添加这样的东西:
str.h:
extern str *str_str(str *, char *);
和str.c
str *str_str(str *buf, char *ns)
{
buf->len = strlen(ns);
buf->buf = (char *) malloc(buf->len + 1);
strncpy(buf->buf, ns, buf->len);
return buf;
}
并且测试效果很好:
str *s = str_new();
printf("%s\n", str_cstr(str_str(s, "hello")));
output: hello
但这会有效吗?
str_assign(s, str_str(s, "ok"));
我认为这基本上是将s
分配给s
。当我打印时,它什么都不打印!
我没有收到任何错误! 非常感谢所有帮助。我是C语言的新手。
str_assign()
的来源:
void str_assign(str *s1, str *s2)
{
s1->len = s2->len;
s1->buf = (char *) malloc(s2->len + 1);
strncpy(s1->buf, s2->buf, s2->len);
}
答案 0 :(得分:2)
我知道这是C,但将它与C ++进行比较是有用的。在C ++中编写赋值运算符时,始终必须考虑自我赋值的情况。当您在C中执行相同的工作时也是如此。
因此,我认为你需要:
void str_assign(str *s1, const str *s2)
{
if (s1 != s2)
{
free(s1->buf); // Added!
s1->len = s2->len;
if ((s1->buf = (char *) malloc(s2->len + 1)) != 0)
memcpy(s1->buf, s2->buf, s2->len + 1);
else
s1->len = 0; // Is this sufficiently safe with a null buf?
}
}
你可以使用memcpy()
因为(a)字符串保证不相交,(b)你知道字符串有多长,所以你不需要检查每个字符串的结尾与strncpy()
或strcpy()
一样的步骤。
实际上,有一种情况表明您永远不需要使用strcpy()
或strncpy()
或strcat()
或strncat()
;你应该总是知道源和目标字符串有多长(否则你不能确定不会有缓冲区溢出),所以你总是可以使用memmove()
或memcpy()
代替。 / p>
我还注意到你将不得不担心内存泄漏。我刚刚修改了上面的赋值以释放旧字符串,然后用新的。
覆盖它您还可以通过仅在新字符串长于旧字符串时分配新空间来优化操作。您也可以考虑使用realloc()
代替malloc()
。但是,您必须小心内存泄漏陷阱。这是使用realloc()
的错误方法:
s1->buf = realloc(s1->buf, s1->len + 1);
如果realloc()
失败,你只是用空值覆盖了你的观点 - 失去了你对旧空间的唯一引用。您应该始终将realloc()
的结果存储在与第一个参数不同的变量中:
char *new_buf = realloc(s1->buf, s1->len + 1);
if (new_buf == 0)
...handle out of memory condition...
您最终可能决定在结构中保留两个长度 - 分配的空间和使用的空间。然后,您可以更有效地重用空间,仅在新字符串长于先前分配的空间时分配更多空间,但仍然允许您随时缩短字符串。
答案 1 :(得分:1)
您需要在str_str
函数中使用return语句,因此请添加return buf;
。
如果您稍微考虑一下,您会发现str_assign
函数中存在错误,因为更改s1->buf
指针后您实际上正在更改s2->buf
因为它们指向到相同的结构。这是一个应该更适合您的实现:
str * str_assign(str * dest, const str * src)
{
char * old_buffer = dest->buf;
if (src->buf)
{
char * buf = malloc(src->len+1);
strncpy(buf, src->buf, src->len);
dest->buf = buf;
dest->len = src->len;
}
else
{
dest->buf = 0;
}
if (old_buffer)
{
free(old_buffer);
}
return dest;
}
答案 2 :(得分:0)
我在以下代码中看到了memory leak
!
void str_assign(str *s1, str *s2)
{
s1->len = s2->len;
s1->buf = (char *) malloc(s2->len + 1);
strncpy(s1->buf, s2->buf, s2->len);
}
如果s1
和s2
指向相同的内存位置,那么您将使用malloc
分配新内存并将其分配给已指向有效内存位置的指针并包含有效的struct str
数据! ..这可以通过执行以下
void str_assign(str *s1, str *s2)
{
if (s1 == s2)
return;
/*
if s1 is pointing to any valid memory
then free it before making it point to
the memory that was allocated by malloc.
*/
if (s1 != NULL)
free(s1);
if ((s1->buf = (char *) malloc(s2->len + 1)) == NULL) {
printf("ERROR: unable to allocate memory\n");
return;
}
s1->len = s2->len;
strncpy(s1->buf, s2->buf, s2->len);
}