将 var 分配给 var —— 会起作用吗?

发布于 2024-12-22 18:34:47 字数 1246 浏览 4 评论 0原文

我正在尝试为我正在开发的包装器做一些有用的事情。我正在为 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);
}

I am trying to do something useful for a wrapper I am working out. I am writing a wrapper for the standard string library for C because I don't like it.

I don't want to introduce C strings to my wrapper right now. Ihave a struct called `str which contains the string's length and the buffer:

struct str
{
    char *buf;
    size_t len;
};

In my header file I have this:

typedef struct str str;

Now I have implemented encapsulation (I think).

So I declare strings like this:

str *a_string = NULL;

I have already done everything that I want to do with this, but I have one problem. What I would like to add something like this for one function:

str.h:

extern str *str_str(str *, char *);

and 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;
}

and testing this works well:

str *s = str_new();
printf("%s\n", str_cstr(str_str(s, "hello")));

output: hello

but will this work?

str_assign(s, str_str(s, "ok"));

That's essentially assigning s to s, I think. When I print, it prints nothing!

I don't get any errors!
All help is greatly appreciated. I am fairly new with the C language.

Source of 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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

じ违心 2024-12-29 18:34:47

我知道这是 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() 代替。


我还注意到,在某些时候您将不得不担心内存泄漏。我刚刚修改了上面的分配以释放旧字符串,然后用新字符串覆盖它。

您还可以通过仅在新字符串比旧字符串长时分配新空间来优化操作。您也可以考虑使用 realloc() 而不是 malloc()。但是,您必须小心内存泄漏陷阱。这是使用 realloc() 的错误方法:

s1->buf = realloc(s1->buf, s1->len + 1);

如果 realloc() 失败,您只是用 null 覆盖了您的点 - 丢失了您对旧空间。您应该始终将 realloc() 的结果存储在与第一个参数不同的变量中:

char *new_buf = realloc(s1->buf, s1->len + 1);
if (new_buf == 0)
    ...handle out of memory condition...

您最终可能决定在结构中保留两个长度 - 分配的空间和使用的空间。然后,您可以更有效地重用空间,仅当新字符串比先前分配的空间长时才分配更多空间,但仍然允许您随时缩短字符串。

I know this is C, but it is useful to compare this with C++. When you write an assignment operator in C++, you always have to consider the case of self-assignment. The same applies when you do the equivalent job in C.

Therefore, I think you need:

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?
    }
}

You can use memcpy() because (a) the strings are guaranteed to be disjoint, and (b) you know how long the string is, so you don't need to check for the end of string at each step of the way as you would with strncpy() or strcpy().

Actually, there's a case for saying you should never need to use strcpy() or strncpy() or strcat() or strncat(); you should always know how long the source and destination strings are (otherwise you can't be sure that there won't be a buffer overflow), so you can always use memmove() or memcpy() instead.


I also note that you're going to have to worry about memory leaks at some point. I just amended the assignment above to release the old string before overwriting it with the new.

You could also optimize operations by only allocating new space when the new string is longer than the old. You could consider using realloc() instead of malloc(), too. However, you must be careful of the memory leak trap. This is the wrong way to use realloc():

s1->buf = realloc(s1->buf, s1->len + 1);

If realloc() fails, you've just overwritten your point with a null - losing the only reference you had to the old space. You should always store the result of realloc() in a different variable from the first argument:

char *new_buf = realloc(s1->buf, s1->len + 1);
if (new_buf == 0)
    ...handle out of memory condition...

You might eventually decide to keep two lengths in your structure - the space allocated and the space used. Then you can reuse space more efficiently, only allocating more space when the new string is longer than the previously allocated space, but still allowing you to shorten a string at any time.

一身骄傲 2024-12-29 18:34:47

您需要在 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;
}

You need to have a return statement in your str_str function, so add return buf;.

If you think about it a little bit you will see there is a bug in your str_assign function because after you change the s1->buf pointer you are actually changing s2->buf also because they point to the same struct. Here is an implementation that should work better for you:

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;
}
樱&纷飞 2024-12-29 18:34:47

我在以下代码中看到内存泄漏

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);
}

如果s1s2指向相同的内存位置,那么您将使用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);
}

I see a memory leak in the following code!

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);
}

if s1 and s2 point to the same memory location, then you're allocating new memory using malloc and assigning it to the pointer which is already pointing to a valid memory location and containing a valid struct str data! .. this can be avoided by putting a simple check by doing the following

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文