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我试着写。)
关于什么的是这样的:如果你把所有的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");
}
是你要记住的malloc为标志字符串的结尾终止null一个额外的字节?
是:'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
。
谢谢。我忘记提及我必须假设'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。
使用你的'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,传递引用,解析的基本元素一个字符串...
希望这会有所帮助, 最好的问候, 汤姆。
@Sneesh:这是一个很好的例子,说明如何在C语言中做到这一点,因为旧格言是'有许多方法可以让皮肤变白......'+1。 – t0mm13b 2010-01-31 12:50:13