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

将分隔的字符串转换为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。)

什么是这样的:

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

如果你在输入中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。

你还记得malloc是一个额外的字节,用于标记字符串结尾的终止空值吗?

从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

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

 #include 
 #include 
 #include 
 #include 

 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-originins = yes ./a.out”;
     ptr = parseInput(str,&maxLen);
     if(!ptr)printf(“Error!\ n”);
    其他{
         for(i = 0; i  0){
         resizeptr(&pStr,++ indx);
         pStr [indx-1] =(char *)malloc(((charPos + 1)* sizeof(char))+ 1);
         if(!pStr [indx-1])返回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!”);
     }其他{
         char ** tmp =(char **)realloc(*(ptr),nLen);
         if(!tmp)perror(“error!”);
         *(ptr)= tmp;
     }
 }

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

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

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