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

问题描述:

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

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

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

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

编辑我必须假设有在inputString令牌任意数量的,所以我不能只是限制它到10什么的。

我试图用strtok和我实现的链表来解决混乱的问题,但是valgrind抱怨太多,我放弃了。

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

+0

@Sneesh:这是一个很好的例子,说明如何在C语言中做到这一点,因为旧格言是'有许多方法可以让皮肤变白......'+1。 – t0mm13b 2010-01-31 12:50:13

关于什么的是这样的:如果你把所有的input输入的开始与

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"); 
} 
+0

实际上,我认为使用指向字符串的256缓冲区不会浪费,除非你真的需要保存内存。 – Jack 2010-01-31 02:42:25

+0

strtok()修改输入字符串,所以在字符串上使用它会在某些时候崩溃平台。 – bk1e 2010-01-31 02:42:40

+0

我可以假设'MAX_ARGS'是安全的,类似于10,000,但代码仍然应该工作10,001个参数... – yavoh 2010-01-31 02:43:18

是你要记住的malloc为标志字符串的结尾终止null一个额外的字节?

+0

是:'char * singleToken =(char *)malloc(strlen(tokPtr)* sizeof(char)+1);''tokPtr'是'strtok'的返回值。 – yavoh 2010-01-31 02:41:44

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

+0

谢谢。我忘记提及我必须假设'inputString'中有任意数量的标记 - 例如,我不能假设为10。 – yavoh 2010-01-31 02:39:00

,那么你永远不能拥有更多的令牌比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。

+0

使用你的'strlen(输入)/ 2'思路 - 谢谢! – yavoh 2010-01-31 03:06:26

查看其他答案,对于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,这意味着当只有3或4个时,双指针已经占用了内存,这也会使得内存使用效率和微小,通过使用realloc,通过使用isspace涵盖了简单的解析,因为它使用指针进行迭代。当遇到一个空格时,realloc使用双指针,而malloc用于保存字符串的偏移量。

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

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