Как я могу заставить строки содержать разделитель после токенизации?

#c

#c

Вопрос:

Я только начал изучать язык C на Ubuntu, я пытался создать простую оболочку, которая работает немного как оболочка. Итак, сразу после того, как я получу командную строку, я думаю, мне, возможно, придется разделить строку разделителем. во-первых, я хочу токенизировать строку с помощью разделителя ‘amp;’, содержащего разделитель, используя «strtok_r ()», но «strcat ()» почему-то не работает с тем, что я хотел

я попытался использовать «strcat ()» после создания токенов. если я использую функцию, вывод первого токена хорошо работает со вторыми токенами, однако они выбрасываются.

вывод просто такой. допустим, у меня есть эти токены.

 token1 : abcde
token2 : fghij
 

и затем, если я использую «strcat (‘amp;’)» с этим, его вывод выглядит так

 token1 : abcdeamp;
token2 : amp;
 

я думаю, это может быть связано с тем, что разделитель, который я пытаюсь поместить в конце «token1», влияет на адрес для «token2».

 #include <stdio.h>
#include <string.h>

int main()
{
        static const char delim[] = "amp;";

        char str[256] = "sleep 5 amp; echo Hello amp; sleep 5; echo Hello";

        char *args[50];

        char *save;
        char *pBuf;
        int i = 0;

        for(pBuf = strtok_r(str, delim, amp;save);
                        pBuf;
                        pBuf = strtok_r(NULL, delim, amp;save)){

                printf("%dn", i);
                args[i  ] = pBuf;

        }


        /** OUT PUT START*/

        i = 0;

        while(args[i]){
                printf("args[%d] : %sn", i , args[i]);
                i  ;
        }

        /**OUT PUT END  */

        return 0;
}
 


 ********OUT PUT

args[0] : sleep 5
args[1] :  echo Hello
args[2] :  sleep 5; echo Hello

********EXPECTED OUT PUT

args[0] : sleep 5 amp;
args[1] : echo Hello amp;
args[2] : sleep 5; echo Hello 
 

Комментарии:

1. Вы должны внимательно изучить руководства. strtok_r заменяет разделитель нулевым байтом завершения. Он не «удаляет начальные пробелы» или «возвращает копии строки». Он работает с str памятью, никакая другая память не используется. Для ввода строки нет памяти amp; . Вам нужно выделить память для ваших нужд, вручную удалить начальные пробелы, добавить разделитель в конец и не забыть освободить выделенную память.

2. Также char *args[50]; не инициализируется, поэтому он имеет «неопределенные» значения, а не NULL. Ваша часть «OUT PUT» имеет неопределенное поведение — while(args[i]) может быть true, args[i] будучи недопустимым указателем.

3. Вы имеете в виду, что если char *pBuf имеет значение Null в первый раз, аргументы [i] могут не инициализироваться?

4. Будет ли он инициализирован, если это будет второй раз? В третий раз? Этого не будет. Будут инициализированы только первые n значений. Например, в вашем коде ошибка seg здесь , потому args[i] что он не инициализирован. Инициализируйте его — добавьте char *args[50] = {0};

Ответ №1:

Вопрос в том, что хорошего strtok в этом случае. Вместо того, чтобы усложнять вещи, вы можете просто выполнить синтаксический анализ вручную strchr . Как только вы найдете разделитель amp; , вы можете ожидать, что в конце будет пробел, и напечатать этот пробел и конец, а не начало. Пример:

 #include <string.h>
#include <stdio.h>

int main(void)
{
  const char str[256] = "sleep 5 amp; echo Hello amp; sleep 5; echo Hello";
  size_t length = strlen(str);

  const char* s1 = str;
  const char* s2;
  const char delim = 'amp;';

  while(s1 < str length)
  {
    s2 = strchr(s1, delim);
    if(s2 == NULL)
    {
      s2 = amp;str[length]; // point at null term
    }
    else
    {
      s2  ; // point at space
    }
    printf("%.*sn", s2-s1, s1); // print (s2-s1) characters
    s1 = s2 1; // point at next char after space, or 1 past null term
  }
}
 

Вывод:

 sleep 5 amp;
echo Hello amp;
sleep 5; echo Hello
 

(Обратите внимание, что в C нормально указывать 1 элемент после конца массива, но не отменять ссылку на этот адрес.)