拆分一串未知数量的单词并使其在函数返回时可用的方法需要一个返回pointer-to-pointer-to-char的函数。这允许一种真正的动态方法,您可以分配一些初始数量的指针(例如2, 4, 8 等。)使用strtok 跟踪使用的指针数量,为每个令牌分配存储空间( word) 随着您的使用,当使用的指针数量等于分配的数量时,您只需 realloc 存储额外的指针并继续前进。
实现函数splitstring() 的简短示例可能类似于以下内容:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NPTR 8 /* initial number of pointers to allocate */
#define MAXD 32 /* maximum no chars for delimiter */
#define MAXC 1024 /* maximum no chars for user input */
char **splitstring (const char *str, const char *delim, size_t *nwords)
{
size_t nptr = NPTR, /* initial pointers */
slen = strlen (str); /* length of str */
char **strings = malloc (nptr * sizeof *strings), /* alloc pointers */
*cpy = malloc (slen + 1), /* alloc for copy of str */
*p = cpy; /* pointer to cpy */
*nwords = 0; /* zero nwords */
if (!strings) { /* validate allocation of strings */
perror ("malloc-strings");
free (cpy);
return NULL;
}
if (!cpy) { /* validate allocation of cpy */
perror ("malloc-cpy");
free (strings);
return NULL;
}
memcpy (cpy, str, slen + 1); /* copy str to cpy */
/* split cpy into tokens */
for (p = strtok (p, delim); p; p = strtok (NULL, delim)) {
size_t len; /* length of token */
if (*nwords == nptr) { /* all pointers used/realloc needed? */
void *tmp = realloc (strings, 2 * nptr * sizeof *strings);
if (!tmp) { /* validate reallocation */
perror ("realloc-strings");
if (*nwords) /* if words stored, return strings */
return strings;
else { /* no words, free pointers, return NULL */
free (strings);
return NULL;
}
}
strings = tmp; /* assign new block to strings */
nptr *= 2; /* update number of allocate pointers */
}
len = strlen (p); /* get token length */
strings[*nwords] = malloc (len + 1); /* allocate storage */
if (!strings[*nwords]) { /* validate allocation */
perror ("malloc-strings[*nwords]");
break;
}
memcpy (strings[(*nwords)++], p, len + 1); /* copy to strings */
}
free (cpy); /* free storage of cpy of str */
if (*nwords) /* if words found */
return strings;
free (strings); /* no strings found, free pointers */
return NULL;
}
int main (void) {
char **strings = NULL,
string[MAXC],
delim[MAXD];
size_t nwords = 0;
fputs ("enter string : ", stdout);
if (!fgets (string, MAXC, stdin)) {
fputs ("(user canceled input)\n", stderr);
return 1;
}
fputs ("enter delimiters: ", stdout);
if (!fgets (delim, MAXD, stdin)) {
fputs ("(user canceled input)\n", stderr);
return 1;
}
if ((strings = splitstring (string, delim, &nwords))) {
for (size_t i = 0; i < nwords; i++) {
printf (" word[%2zu]: %s\n", i, strings[i]);
free (strings[i]);
}
free (strings);
}
else
fputs ("error: no delimiter found\n", stderr);
}
(注意:字数 nwords 作为指向 splitstring() 函数的指针传递,以允许在函数内更新字数并在调用函数中返回, 同时从函数本身返回一个 pointer-to-pointer-to-char)
使用/输出示例
$ ./bin/stringsplitdelim
enter string : my dog has fleas and my cat has none and snakes don't have fleas
enter delimiters:
word[ 0]: my
word[ 1]: dog
word[ 2]: has
word[ 3]: fleas
word[ 4]: and
word[ 5]: my
word[ 6]: cat
word[ 7]: has
word[ 8]: none
word[ 9]: and
word[10]: snakes
word[11]: don't
word[12]: have
word[13]: fleas
(注意:' '(空格)作为分隔符被输入到上面,导致 delim 包含 " \n"(正是你想要的),因为使用了面向行的输入函数fgets供用户输入)
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。
对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。
$ valgrind ./bin/stringsplitdelim
==12635== Memcheck, a memory error detector
==12635== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==12635== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==12635== Command: ./bin/stringsplitdelim
==12635==
enter string : my dog has fleas and my cat has none and snakes don't have fleas
enter delimiters:
word[ 0]: my
word[ 1]: dog
word[ 2]: has
word[ 3]: fleas
word[ 4]: and
word[ 5]: my
word[ 6]: cat
word[ 7]: has
word[ 8]: none
word[ 9]: and
word[10]: snakes
word[11]: don't
word[12]: have
word[13]: fleas
==12635==
==12635== HEAP SUMMARY:
==12635== in use at exit: 0 bytes in 0 blocks
==12635== total heap usage: 17 allocs, 17 frees, 323 bytes allocated
==12635==
==12635== All heap blocks were freed -- no leaks are possible
==12635==
==12635== For counts of detected and suppressed errors, rerun with: -v
==12635== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放已分配的所有内存并且没有内存错误。
查看一下,如果您还有其他问题,请告诉我。