C: создание массива строк от разграниченной исходной строки

Каков был бы эффективный способ преобразовать разграниченную строку в массив строк в 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, которую я пытаюсь записать.)

5
задан yavoh 31 January 2010 в 02:39
поделиться

5 ответов

Что-то вроде:

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");
}
2
ответ дан 14 December 2019 в 13:36
поделиться

Если у вас есть весь вход в вход , чтобы начать с того, что вы никогда не можете иметь больше токенов, чем 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 для каждого токена, если по какой-то причине вы не нужно , чтобы освободить их индивидуально.

2
ответ дан 14 December 2019 в 13:36
поделиться

Вы помняли на Malloc дополнительный байт для завершения NULL это отмечает конец строки?

1
ответ дан 14 December 2019 в 13:36
поделиться

из 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.

1
ответ дан 14 December 2019 в 13:36
поделиться

, глядя на другие ответы, для начинающего в 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 , базовый элемент разборки строки ...

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

0
ответ дан 14 December 2019 в 13:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: