Вы можете делать именно то, что вы пытаетесь, но если вы объявите массив указателей с automati c срок хранения , то вы должны обязательно ограничить количество токены, которые вы назначаете номеру, который вы объявляете для защиты границ вашего массива. Вам также следует рассмотреть возможность выделения 1 дополнительного указателя, чтобы позволить вам сохранить NULL
в качестве следующего указателя после вашего последнего действующего токена, который будет служить sentinel NULL
, отмечающим конец действительных указателей в вашем массиве. (как это делается с *argv[]
и требуется для функций execv
, execvp
и execve
)
Для работы с string-literal , без изменений строки input
. Самый простой способ обработки разделительных слов в ' '
(пробел) - просто использовать пару указателей (указатель начала и конца), где вы перемещаете указатель конца вниз по строке, пока не найдете пробел, а затем выделяете память для количества символов между началом и концом (+1 для символа, заканчивающегося нулем ), а затем просто скопируйте символы в только что выделенное хранилище и завершите строку строкой.
Когда ваш l oop продвигает ваш указатель конца на единицу, чтобы он указывал на следующий символ после пробела, установите указатель начала на указатель конца, чтобы он находился в начале следующего токена. Переместите ваш массив указателей указателя к следующему указателю и установите для NULL
для стража после копирования каждого слова.
Кроме того, вам нужно сохранить переменную состояния, простую int
для использования в качестве 1 (true)/0 (false)
флаг для отслеживания, если вы in-word читаете символы или out читаете пробелы. Это позволяет пропускать начальные пробелы, несколько включенных пробелов между токенами или конечные пробелы после последнего токена. Это позволяет вам разделить "ls -l"
или " ls -l "
на те же два токена "ls"
и "-l"
.
Ваш parseUserInput()
может быть записан как:
#define MAXARG 6
void parseUserInput (char **userInput, const char *input)
{
int i = 0, in = 0; /* index, and in/out of word flag */
const char *p = input, *ep = p; /* pointer and end-pointer */
while (i < MAXARG) { /* loop while pointers remain */
if (!*ep || *ep == ' ') { /* if at nul-char or space */
size_t len = ep - p; /* get length of token */
if (in && len) { /* in-word and chars in token */
/* allocate/validate storage for token */
if (!(userInput[i] = malloc (len + 1))) {
perror ("malloc-userInput[i]");
break;
}
memcpy (userInput[i], p, len); /* copy len chars to storage */
userInput[i++][len] = 0; /* nul-terminate, advance index */
userInput[i] = NULL; /* set next pointer NULL */
}
if (!*ep) /* if at end, break */
break;
in = 0; /* set in-word flag 0 (false) */
}
else { /* normal word char */
if (!in) /* if not in-word */
p = ep; /* update start to end-pointer */
in = 1; /* set in-word flag 1 (true) */
}
ep++; /* advance to next character */
}
}
( примечание: порядок параметров переключается, чтобы порядок соответствовал strcpy
, memcpy
, et c ...)
Добавление короткого main()
с свой пример вы можете сделать:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXARG 6
void parseUserInput (char **userInput, const char *input)
{
int i = 0, in = 0; /* index, and in/out of word flag */
const char *p = input, *ep = p; /* pointer and end-pointer */
while (i < MAXARG) { /* loop while pointers remain */
if (!*ep || *ep == ' ') { /* if at nul-char or space */
size_t len = ep - p; /* get length of token */
if (in && len) { /* in-word and chars in token */
/* allocate/validate storage for token */
if (!(userInput[i] = malloc (len + 1))) {
perror ("malloc-userInput[i]");
break;
}
memcpy (userInput[i], p, len); /* copy len chars to storage */
userInput[i++][len] = 0; /* nul-terminate, advance index */
userInput[i] = NULL; /* set next pointer NULL */
}
if (!*ep) /* if at end, break */
break;
in = 0; /* set in-word flag 0 (false) */
}
else { /* normal word char */
if (!in) /* if not in-word */
p = ep; /* update start to end-pointer */
in = 1; /* set in-word flag 1 (true) */
}
ep++; /* advance to next character */
}
}
int main (void) {
char *in = "ls -l",
*parsedInput[MAXARG + 1] = { NULL }; /* add +1 for sentinel NULL at end */
parseUserInput (parsedInput, in); /* note: parameter order change */
for (char **p = parsedInput; *p; p++) { /* loop over filled pointers */
puts (*p);
free (*p); /* don't forget to free what you allocate */
}
}
( примечание: не забудьте free()
выделенное вами хранилище)
Пример Использование / Вывод
$ ./bin/splitinput
ls
-l
Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.