5

将分隔字符串转换为 C(不是 C++)中的字符串数组的有效方法是什么?例如,我可能有:

char *input = "valgrind --leak-check=yes --track-origins=yes ./a.out"

源字符串将始终只有一个空格作为分隔符。我想要一个 malloc 的 malloc 字符串数组,char *myarray[]这样:

myarray[0]=="valgrind"
myarray[1]=="--leak-check=yes"
...

编辑我必须假设其中有任意数量的令牌,inputString所以我不能将其限制为 10 或其他东西。

我尝试了一个凌乱的解决方案strtok和一个我已经实现的链表,但 valgrind 抱怨太多以至于我放弃了。

(如果您想知道,这是针对我正在尝试编写的基本 Unix shell 的。)

4

5 回答 5

2

如果您一input开始就拥有所有输入,那么您永远不会拥有比strlen(input). 如果您不允许 "" 作为令牌,那么您永远不能拥有多个strlen(input)/2令牌。所以除非input巨大的,否则你可以安全地写。

char ** myarray = malloc( (strlen(input)/2) * sizeof(char*) );

int NumActualTokens = 0;
while (char * pToken = get_token_copy(input))
{ 
   myarray[++NumActualTokens] = pToken;
   input = skip_token(input);
}

char ** myarray = (char**) realloc(myarray, NumActualTokens * sizeof(char*));

作为进一步的优化,您可以保留input并用 \0 替换空格,并将指向input缓冲区的指针放入 myarray[]。除非出于某种原因您需要单独释放它们,否则每个令牌都不需要单独的 malloc 。

于 2010-01-31T02:52:06.213 回答
2

什么是这样的:

char* string = "valgrind --leak-check=yes --track-origins=yes ./a.out";
char** args = (char**)malloc(MAX_ARGS*sizeof(char*));
memset(args, 0, sizeof(char*)*MAX_ARGS);

char* curToken = strtok(string, " \t");

for (int i = 0; curToken != NULL; ++i)
{
  args[i] = strdup(curToken);
  curToken = strtok(NULL, " \t");
}
于 2010-01-31T02:38:42.117 回答
1

您是否记得为标记字符串结尾的终止 null 分配一个额外的字节?

于 2010-01-31T02:34:23.793 回答
1

strsep(3)OSX 的手册页:

   char **ap, *argv[10], *inputstring;

   for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;)
           if (**ap != '\0')
                   if (++ap >= &argv[10])
                           break;

针对任意数量的令牌进行了编辑:

char **ap, **argv, *inputstring;

int arglen = 10;
argv = calloc(arglen, sizeof(char*));
for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;)
    if (**ap != '\0')
        if (++ap >= &argv[arglen])
        {
            arglen += 10;
            argv = realloc(argv, arglen);
            ap = &argv[arglen-10];
        }

或者类似的东西。上面的方法可能行不通,但如果不行,那也不远了。建立一个链表会比不断调用更有效realloc,但这真的不是重点——重点是如何最好地利用strsep.

于 2010-01-31T02:36:49.407 回答
0

看看其他答案,对于 C 语言的初学者来说,由于代码的大小,它看起来很复杂,我想我会把它放在初学者身上,实际解析字符串而不是使用strtok...像这样的东西:

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

char **parseInput(const char *str, int *nLen);
void resizeptr(char ***, int nLen);

int main(int argc, char **argv){
    int maxLen = 0;
    诠释 i = 0;
    字符 **ptr = NULL;
    char *str = "valgrind --leak-check=yes --track-origins=yes ./a.out";
    ptr = parseInput(str, &maxLen);
    if (!ptr) printf("错误!\n");
    别的{
        for (i = 0; i < maxLen; i++) printf("%s\n", ptr[i]);
    }
    对于 (i = 0; i < maxLen; i++) 自由(ptr[i]);
    免费(ptr);
    返回0;
}

char **parseInput(const char *str, int *Index){
    字符 **pStr = NULL;
    字符 *ptr = (char *)str;
    int charPos = 0, indx = 0;
    而 (ptr++ && *ptr){
        if (!isspace(*ptr) && *ptr) charPos++;
        别的{
            调整大小 (&ptr, ++indx);
            pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1);
            如果 (!pStr[indx-1]) 返回 NULL;
            strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1);
            pStr[indx-1][charPos+1]='\0';
            字符位置 = 0;
        }
    }
    如果(字符位置> 0){
        resizeptr(&pStr, ++indx);
        pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1);
        如果 (!pStr[indx-1]) 返回 NULL;
        strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1);
        pStr[indx-1][charPos+1]='\0';
    }
    *索引=索引;
    返回 (char **)pStr;
}

void resizeptr(char ***ptr, int nLen){
    if (*(ptr) == (char **)NULL){
        *(ptr) = (char **)malloc(nLen * sizeof(char*));
        if (!*(ptr)) perror("error!");
    }别的{
        char **tmp = (char **)realloc(*(ptr),nLen);
        if (!tmp) perror("错误!");
        *(ptr) = tmp;
    }
}

我稍微修改了代码以使其更容易。我使用的唯一字符串函数是strncpy..确保它有点冗长,但它确实动态重新分配字符串数组而不是使用硬编码的 MAX_ARGS,这意味着双指针在只有 3 时已经占用了内存或 4 会做,这也将使内存使用效率和微小,通过 using realloc,简单的解析被employing 覆盖isspace,因为它使用指针进行迭代。当遇到空格时,它会realloc吃掉双指针和malloc保存字符串的偏移量。

请注意函数中如何使用三重指针resizeptr。事实上,我认为这将成为一个简单 C 程序、指针、realloc、malloc、按引用传递、解析字符串的基本元素的一个很好的例子......

希望这会有所帮助,最好的问候,汤姆。

于 2010-01-31T03:21:25.890 回答