我有一个字符串,例如:
char* cmd = "a bcd ef hijk lmmopq";
字符串由按空格分割的段组成,段数不固定。
直观地说,我可以通过动态分配内存来获取2D字符串,例如:
char** argv = malloc();
char* argv[0] = malloc();
...
char* argv[i] = malloc();
但我可以将原始数组转换为2d char数组,如下所示,以避免内存分配吗?
char* argv[] = {"a", "bcd", "ef", "hijk", "lmmopq"};
答案 0 :(得分:1)
正如另一个答案中所指出的,strtok
可用于将字符串就地分割,以便用空终止符替换分隔符(空格)。
要知道会有多少个字符串,你必须遍历字符串两次。对于第一次迭代,发明一些快速&简单的函数,不会改变字符串,如下所示:
size_t count_spaces (const char* src)
{
size_t spaces=0;
for(; *src != '\0'; src++)
{
if(*src == ' ')
{
spaces++;
}
}
return spaces;
}
然后对于第二次迭代,使用strtok
。完整的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t count_spaces (const char* src)
{
size_t spaces=0;
for(; *src != '\0'; src++)
{
if(*src == ' ')
{
spaces++;
}
}
return spaces;
}
void tokenize (char* restrict src,
size_t dst_size,
char* restrict dst [dst_size])
{
size_t i;
char* ptr = strtok(src, " ");
for(i=0; i<dst_size && ptr != NULL; i++)
{
dst[i] = ptr;
ptr = strtok(NULL, " ");
}
}
int main (void)
{
char str [] = "a bcd ef hijk lmmopq";
size_t size = count_spaces(str) + 1;
char* ptr_arr [size];
tokenize(str, size, ptr_arr);
for(size_t i=0; i<size; i++)
{
puts(ptr_arr[i]);
}
}
答案 1 :(得分:0)
继续发表评论,您可以标记化您的字符串,例如strtok
并将指向单个单词的指针分配给指向指针指向char 的指针。例如:
#include <stdio.h>
#include <string.h>
#define MAX 10
int main (void) {
char *cmd = (char[]){"a bcd ef hijk lmmopq"}, /* compound literal */
// char cmd[] = "a bcd ef hijk lmmopq"; /* otherwise declare as array */
*arr[MAX] = {NULL},
*delim = " \n";
size_t n = 0;
for (char *p = strtok (cmd, delim); n < MAX && p; p = strtok (NULL, delim))
arr[n++] = p;
for (int i = 0; i < (int)n; i++)
printf ("arr[%d]: %s\n", i, arr[i]);
return 0;
}
*示例使用/输出**
$./bin/str2ptp
arr[0]: a
arr[1]: bcd
arr[2]: ef
arr[3]: hijk
arr[4]: lmmopq
注意:您无法将 字符串文字 传递给strtok
,因为strtok
会修改字符串。要么使用指向数组的指针,要么声明并初始化为正常的char[]
数组。
动态分配未知字数的指针
如果您不知道是否可以读取20个单词或2000个单词,则可以通过动态分配指针块来轻松处理这种情况,然后再次realloc
再次进行先前的最大分配。这是一个简单的过程,例如
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10
#define MAXB 4096
int main (void) {
char cmd[MAXB] = "", /* buffer of 4096 chars to hold each line input */
**arr = calloc (MAX, sizeof *arr),
*delim = " \n";
size_t n = 0, max = MAX;
while (fgets (cmd, MAXB, stdin)) { /* read each line of input on stdin */
size_t len = strlen (cmd); /* get line length */
if (cmd[len - 1] == '\n') /* test for trailing '\n' */
cmd[--len] = 0; /* overwrite with nul-byte */
for (char *p = strtok (cmd, delim); p; p = strtok (NULL, delim)) {
arr[n++] = p;
if (n == max) { /* realloc arr by MAX if n == MAX */
void *tmp = realloc (arr, (max + MAX) * sizeof *arr);
if (!tmp) {
fprintf (stderr, "error: memory exhausted.\n");
break;
}
arr = tmp; /* zero new pointers (optional) */
memset (arr + max, 0, MAX * sizeof *arr);
max += MAX; /* update current max iteration */
}
}
for (int i = 0; i < (int)n; i++)
printf ("arr[%2d]: %s\n", i, arr[i]);
}
free (arr); /* don't forget, if you allocate it -> you free it. */
return 0;
}
以上,始终使用以下方式验证您的分配:为简洁起见,if (!arr) { /* handle error */ }
的初始分配中省略了arr
。
使用/输入示例
$ echo "A quick brown fox jumps over the lazy dog while the dog watched" | \
./bin/strtop2pdyn
arr[ 0]: A
arr[ 1]: quick
arr[ 2]: brown
arr[ 3]: fox
arr[ 4]: jumps
arr[ 5]: over
arr[ 6]: the
arr[ 7]: lazy
arr[ 8]: dog
arr[ 9]: while
arr[10]: the
arr[11]: dog
arr[12]: watched