我正在尝试将
char32_t
字符串拆分为由分隔符分隔的标记。我没有使用任何 strtok 或其他 std 库函数,因为输入字符串和定界符将是多字节 unicode 字符串。
这是我写的函数:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uchar.h>
#include <wchar.h>
char32_t **sp(char32_t *str, char32_t delim, int *len) {
*len = 1;
char32_t *s = str;
while (*s != U'\0') {
if (*s == delim) {
(*len)++;
}
s++;
}
char32_t **tokens = (char32_t **)malloc((*len) * sizeof(char32_t *));
if (tokens == NULL) {
exit(111);
}
char32_t * p = str;
int i = 0;
while (*p != U'\0') {
int tok_len = 0;
while (p[tok_len] != U'\0' && p[tok_len] != delim) {
tok_len++;
}
tokens[i] = (char32_t *)malloc(sizeof(char32_t) * (tok_len + 1));
if (tokens[i] == NULL) {
exit(112);
}
memcpy(tokens[i], p, tok_len * sizeof(char32_t));
tokens[i][tok_len] = U'\0';
p += tok_len + 1;
i++;
}
return tokens;
}
这是驱动程序代码
int main() {
char32_t *str = U"Hello,World,mango,hey,";
char32_t delim = U',';
int len = 0;
char32_t ** tokens = sp(str, delim, &len);
wprintf(L"len -> %d\n", len);
for (int i = 0; i < len; i++) {
if (tokens[i]) {
wprintf(L"[%d] %ls\n" , i , tokens[i]);
}
free(tokens[i]);
}
free(tokens);
}
这里是输出:
len -> 5
[0] Hello
[1] World
[2] mango
[3] hey
[4] (null)
但是当我用 valgrind 检查程序时,它显示多个内存错误
valgrind -s --leak-check=full --track-origins=yes ./x3
==7703== Memcheck, a memory error detector
==7703== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==7703== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==7703== Command: ./x3
==7703==
tok -> 5
tok -> 5
tok -> 5
tok -> 3
len -> 5
[0] Hello
[1] World
[2] mango
[3] hey
==7703== Conditional jump or move depends on uninitialised value(s)
==7703== at 0x48FDAF8: __wprintf_buffer (vfprintf-process-arg.c:396)
==7703== by 0x48FF421: __vfwprintf_internal (vfprintf-internal.c:1459)
==7703== by 0x490CFAE: wprintf (wprintf.c:32)
==7703== by 0x1093C9: main (main.c:51)
==7703== Uninitialised value was created by a heap allocation
==7703== at 0x4841888: malloc (vg_replace_malloc.c:393)
==7703== by 0x1091FC: sp (main.c:17)
==7703== by 0x109384: main (main.c:47)
==7703==
[4] (null)
==7703== Conditional jump or move depends on uninitialised value(s)
==7703== at 0x4844225: free (vg_replace_malloc.c:884)
==7703== by 0x1093DA: main (main.c:52)
==7703== Uninitialised value was created by a heap allocation
==7703== at 0x4841888: malloc (vg_replace_malloc.c:393)
==7703== by 0x1091FC: sp (main.c:17)
==7703== by 0x109384: main (main.c:47)
==7703==
==7703==
==7703== HEAP SUMMARY:
==7703== in use at exit: 0 bytes in 0 blocks
==7703== total heap usage: 7 allocs, 7 frees, 5,248 bytes allocated
==7703==
==7703== All heap blocks were freed -- no leaks are possible
==7703==
==7703== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==7703==
==7703== 1 errors in context 1 of 2:
==7703== Conditional jump or move depends on uninitialised value(s)
==7703== at 0x4844225: free (vg_replace_malloc.c:884)
==7703== by 0x1093DA: main (main.c:52)
==7703== Uninitialised value was created by a heap allocation
==7703== at 0x4841888: malloc (vg_replace_malloc.c:393)
==7703== by 0x1091FC: sp (main.c:17)
==7703== by 0x109384: main (main.c:47)
==7703==
==7703==
==7703== 1 errors in context 2 of 2:
==7703== Conditional jump or move depends on uninitialised value(s)
==7703== at 0x48FDAF8: __wprintf_buffer (vfprintf-process-arg.c:396)
==7703== by 0x48FF421: __vfwprintf_internal (vfprintf-internal.c:1459)
==7703== by 0x490CFAE: wprintf (wprintf.c:32)
==7703== by 0x1093C9: main (main.c:51)
==7703== Uninitialised value was created by a heap allocation
==7703== at 0x4841888: malloc (vg_replace_malloc.c:393)
==7703== by 0x1091FC: sp (main.c:17)
==7703== by 0x109384: main (main.c:47)
==7703==
==7703== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
我无法弄清楚问题是什么。任何帮助将不胜感激
我也尝试过使用 unicode 字符串,同样的错误也会发生。
valgrind
给出这些错误是因为您的程序在 for
函数 中的这个
main()
循环的最后一次迭代中访问未初始化的内存(即在访问 tokens[4]
时,当 len
值为 5
):
for (int i = 0; i < len; i++) {
if (tokens[i]) {
wprintf(L"[%d] %ls\n" , i , tokens[i]);
}
free(tokens[i]);
}
要解决这个问题,在
sp()
函数中,在为tokens
分配内存后,要么这样做:
tokens [*len - 1]= NULL;
或使用
calloc
分配内存给tokens
:
char32_t **tokens = calloc((*len), sizeof(char32_t *));
使用上述任何一种解决方案,
valgrind
输出:
# valgrind -s --leak-check=full --track-origins=yes ./a.out
==9761== Memcheck, a memory error detector
==9761== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9761== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==9761== Command: ./a.out
==9761==
len -> 5
[0] Hello
[1] World
[2] mango
[3] hey
==9761==
==9761== HEAP SUMMARY:
==9761== in use at exit: 0 bytes in 0 blocks
==9761== total heap usage: 7 allocs, 7 frees, 5,248 bytes allocated
==9761==
==9761== All heap blocks were freed -- no leaks are possible
==9761==
==9761== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)