7

我想解析一个字符串,我使用strsep函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

  char str[] = "Marco:Q:2F7PKC";
  char *token1, *token2, *token3;
  char *r = malloc(30);

  strcpy(r, str);

  token1 = strsep(&r, ":");
  token2 = strsep(&r, ":");
  token3 = strsep(&r, ":");

  printf("tok1 = %s\n", token1);
  printf("tok2 = %s\n", token2);
  printf("tok3 = %s\n", token3);

  free(r);

  return 0;

}

该函数很好地完成了它的工作,但是如果我启动valgrind,分配的字符串char * r不会正确释放(肯定会丢失:1 个块中的 30 个字节)。

我想知道为什么以及是否有其他方法可以做同样的事情,也许不需要调用strsep

我打电话给 valgrindvalgrind --tool=memcheck --leak-check=full --show-reachable=yes ./a.out

4

3 回答 3

21

strsep覆盖其第一个(指针到指针)参数的目标,因此您丢失了指向malloc'd 缓冲区基址的指针。事实上,如果你确实在printf("%p\n", r);之前放了 a free,你会发现你正在释放一个空指针,这没有任何效果。

简单的解决方案是引入一个额外的变量来保留该指针,并free在完成后保留它。惯用用法是

char *r = strdup("Marco:Q:3F7PKC");
// check for errors

char *tok = r, *end = r;
while (tok != NULL) {
    strsep(&end, ":");
    puts(tok);
    tok = end;
}

free(r);
于 2014-01-27T14:16:40.043 回答
4

我想稍微简化一下 Fred Foo 的一个很好的回复:

char *end, *r, *tok;

r = end = strdup("Marco:Q:3F7PKC");
assert(end != NULL);

while ((tok = strsep(&end, ":")) != NULL) {
    printf("%s\n", tok);
}

free(r);

它给出了相同的结果。但值得一提的是,strsep(3)将分隔符后的下一个值存储到end变量中并返回当前值(到tok变量中)。

于 2017-09-14T21:57:11.753 回答
1

strsep 函数更新它的第一个参数(因此它指向它找到的标记之后)。您需要将 malloc 返回的值存储在单独的变量中并释放该变量。

于 2014-01-27T14:18:17.097 回答