Каков был бы эффективный способ преобразовать разграниченную строку в массив строк в C (не C++)? Например, я мог бы иметь:
char *input = "valgrind --leak-check=yes --track-origins=yes ./a.out"
Исходная строка будет всегда иметь только одиночный пробел как разделитель. И я хотел бы malloc'ed массив строк malloc'ed char *myarray[]
таким образом, что:
myarray[0]=="valgrind"
myarray[1]=="--leak-check=yes"
...
Редактирование я должен предположить, что существует произвольное число маркеров в inputString
таким образом, я не могу просто ограничить его 10 или что-то.
Я делал попытку грязного решения с strtok
и связанный список, который я реализовал, но valgrind жаловался так, что я сдался.
(Если Вы задаетесь вопросом, это для основной оболочки Unix, которую я пытаюсь записать.)
Что-то вроде:
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");
}
Если у вас есть весь вход в вход
, чтобы начать с того, что вы никогда не можете иметь больше токенов, чем STRLEN (вход)
. Если вы не допустите «» в качестве токена, вы никогда не можете иметь более Стрелок (вход) / 2
токенов. Итак, если ввод
Огромный Вы можете безопасно написать.
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*));
В качестве дополнительной оптимизации вы можете сохранить вход
и просто заменить пробелы с \ 0 и помещать указатели в вход
в буфер в Myarlay []. Нет необходимости в отдельном Malloc для каждого токена, если по какой-то причине вы не нужно , чтобы освободить их индивидуально.
Вы помняли на Malloc дополнительный байт для завершения NULL это отмечает конец строки?
из strsep(3)
manpage на OSX:
char **ap, *argv[10], *inputstring;
for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;)
if (**ap != '\0')
if (++ap >= &argv[10])
break;
Edited for arbitrary # of tokens:
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 <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
ALLOC с двойным указателем, а Malloc
смещение для удержания строки.
Обратите внимание, как используются тройные указатели в Resizeptr
.. На самом деле, я подумал, что это будет служить отличным примером простой C программы C, указатели, Realloc, Malloc, Passing-By , базовый элемент разборки строки ...
Надеюсь, это поможет, С наилучшими пожеланиями, Том.