C:从分隔的源字符串创建字符串数组

时间:2010-01-31 02:29:27

标签: c arrays strtok

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

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

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

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

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

我尝试使用strtok和我已实施的链接列表的混乱解决方案,但valgrind抱怨太多,我放弃了。

(如果你想知道,这是我想写的基本Unix shell。)

5 个答案:

答案 0 :(得分: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");
}

答案 1 :(得分: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。

答案 2 :(得分:1)

你是否还记得malloc为终止空值的额外字节标记字符串的结尾?

答案 3 :(得分:1)

来自OSX的strsep(3)联机帮助页:

   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

答案 4 :(得分: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;
    int i = 0;
    char **ptr = NULL;
    char *str = "valgrind --leak-check=yes --track-origins=yes ./a.out";
    ptr = parseInput(str, &maxLen);
    if (!ptr) printf("Error!\n");
    else{
        for (i = 0; i < maxLen; i++) printf("%s\n", ptr[i]);
    }
    for (i = 0; i < maxLen; i++) free(ptr[i]);
    free(ptr);
    return 0;
}

char **parseInput(const char *str, int *Index){
    char **pStr = NULL;
    char *ptr = (char *)str;
    int charPos = 0, indx = 0;
    while (ptr++ && *ptr){
        if (!isspace(*ptr) && *ptr) charPos++;
        else{
            resizeptr(&ptr, ++indx);
            pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1);
            if (!pStr[indx-1]) return NULL;
            strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1);
            pStr[indx-1][charPos+1]='\0';
            charPos = 0;
        }
    }
    if (charPos > 0){
        resizeptr(&pStr, ++indx);
        pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1);
        if (!pStr[indx-1]) return NULL;
        strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1);
        pStr[indx-1][charPos+1]='\0';
    }
    *Index = indx;
    return (char **)pStr;
}

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

我稍微修改了代码以使其更容易。我使用的唯一字符串函数是strncpy ..确定它有点啰嗦但它确实动态地重新分配字符串数组而不是使用硬编码的MAX_ARGS,这意味着双指针已经占用了通过使用realloc,当只有3或4时,内存使用效率会很高,并且使用isspace进行简单解析,因为它使用指针进行迭代。遇到空格时,realloc会使用双指针,malloc会保留字符串。

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

希望这有帮助, 最好的祝福, 汤姆。