Перейти к содержанию
    

Парсинг строки.

Делаю так

uint32_t ParseCommandArguments(char *str, char *com, char arg[4][20])
{
    uint32_t char_idx = 0;
    uint32_t arg_idx = 0;
     while(*str)
    {
        if(*str != 32) //not space
        {
            if(arg_idx==0)  //command
            {
                com[char_idx++] = *str;
             }
            else  //arguments
            {
                arg[arg_idx-1][char_idx++] = *str;
            }
        }
        else  // space 
       {
            char_idx = 0;
            arg_idx++;
        }
        str++;
    }
    return arg_idx;
}

и потом

char *str = "run arg1 arg2";
char *command="";
char arguments[4][20];

uint32_t argc = ParseCommandArguments(str, command, arguments);
  
UART_SendString(UART0,command);
UART_SendString(UART0,arguments[0]);
UART_SendString(UART0,arguments[1]);
UART_SendInt(UART0,argc);

когда иду в отладке шаг за шагом вроде все чары попадают куда нужно, но на выходе нулевые строки. что за чудеса?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Делаю так

char *command="";

То есть под command вы отвели место ровно в один символ - символ конца строки.

                com[char_idx++] = *str;

А теперь вылезли за пределы command и пошли портить соседние данные.

 

Возможно есть и другие причины, но сначала надо устранить эту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может проще парсить команду при помощи strtok в массив указателей?

http://www.cplusplus.com/reference/cstring/strtok/

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть под command вы отвели место ровно в один символ - символ конца строки.

А теперь вылезли за пределы command и пошли портить соседние данные.

 

Возможно есть и другие причины, но сначала надо устранить эту.

Исправил char *command=""; на char *command; не помогло

char_idx я обнуляю в начале и потом он обнуляется на каждом разделительном чаре - в данном случае пробел.

 

 

 

 

Может проще парсить команду при помощи strtok в массив указателей?

http://www.cplusplus.com/reference/cstring/strtok/

я пробовал так

void Split(char *str, char *com, char arg[4][20])
{
  uint32_t arg_idx = 0;
  char * pch;
  pch = strtok (str," ");
  strncpy(com,pch,strlen(pch));
  while (pch != NULL)
  {
    pch = strtok (NULL, " ");
    strncpy(arg[arg_idx++],pch,strlen(pch));
  }
}

тот же результат

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

char command[64];

 

if(arg_idx==0) //command

{

com[char_idx++] = *str;

com[char_idx] = 0;

}

else //arguments

{

arg[arg_idx-1][char_idx++] = *str;

arg[arg_idx-1][char_idx] = 0;

}

Изменено пользователем Herz
Избыточное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

char command[64];

 

if(arg_idx==0) //command

{

com[char_idx++] = *str;

com[char_idx] = 0;

}

else //arguments

{

arg[arg_idx-1][char_idx++] = *str;

arg[arg_idx-1][char_idx] = 0;

}

 

да, так работает. спасибо. странно - компайлер обычно закрывает все строки с '\0'.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Исправил char *command=""; на char *command; не помогло
Еще лучше. Сначала вы заводили массив из одного байта ("") и объявляли указатель (command *), указывающий на начало этого массива. После чего, двигая указатель уходили за пределы массива, круша все, что попадалось на пути. Теперь вы просто завели указатель, показывающий куда попало (потому что неиницимализированный и содержащий мусор из памяти) и начали крушить уже где попало. Не удивлюсь, если компилятор выдал предупреждение об этом, но вы на это предупреждение забили.

 

странно - компайлер обычно закрывает все строки с '\0'.
Компилятор автоматически добавляет завершающий ноль к строковым литералам. Он не обладает телепатическими свойствами чтобы понять, что выражением "arg[arg_idx-1][char_idx++] = *str;" вы создаете новую строку - для него это просто копирование символа из одного места в другое. Только копирование и ничего более.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще лучше. Сначала вы заводили массив из одного байта ("") и объявляли указатель (command *), указывающий на начало этого массива. После чего, двигая указатель уходили за пределы массива, круша все, что попадалось на пути. Теперь вы просто завели указатель, показывающий куда попало (потому что неиницимализированный и содержащий мусор из памяти) и начали крушить уже где попало. Не удивлюсь, если компилятор выдал предупреждение об этом, но вы на это предупреждение забили.

 

неа, молчит гад, не ругается.

и кстати почему так работает?

char *command="";

command = strtok(str," ");

 

Компилятор автоматически добавляет завершающий ноль к строковым литералам. Он не обладает телепатическими свойствами чтобы понять, что выражением "arg[arg_idx-1][char_idx++] = *str;" вы создаете новую строку - для него это просто копирование символа из одного места в другое. Только копирование и ничего более.

 

но последний символ строки он ведь '\0'. у меня же нет index overflow.

 

да и кстати он таки телепат -у меня фиксированные строки char arguments[4][20];

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я пробовал так

void Split(char *str, char *com, char arg[4][20])
{
  uint32_t arg_idx = 0;
  char * pch;
  pch = strtok (str," ");
  strncpy(com,pch,strlen(pch));
  while (pch != NULL)
  {
    pch = strtok (NULL, " ");
    strncpy(arg[arg_idx++],pch,strlen(pch));
  }
}

тот же результат

 

По идее как-то так д.б. :

#define ARGS_MAX        16
#define ARGS_DELIM      " "

static char* args[ARGS_MAX]={ NULL };

int parse_command(char* str, char** args)
{
    int argc=0;

    args[argc] = strtok (str, ARGS_DELIM);

    while (args[argc] != NULL)
    {
        if(argc >= ARGS_MAX)
            break;
        args[++argc] = strtok (NULL, ARGS_DELIM);
    }

    return argc;
}

void uart_send_string(int uart, char* command)
{
    printf("send: %s\n", command);
}

int main ()
{
    char str[] = "run arg1 arg2";
    int argc, i;

    argc = parse_command(str, args);

    for(i=0;i<argc; i++)
    {
        uart_send_string(1, args[i]);
    }

    return 0;
}

непонятно только, зачем отправлять команду в порт порциями?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По идее как-то так д.б. :

#define ARGS_MAX        16
#define ARGS_DELIM      " "

static char* args[ARGS_MAX]={ NULL };

int parse_command(char* str, char** args)
{
    int argc=0;

    args[argc] = strtok (str, ARGS_DELIM);

    while (args[argc] != NULL)
    {
        if(argc >= ARGS_MAX)
            break;
        args[++argc] = strtok (NULL, ARGS_DELIM);
    }

    return argc;
}

void uart_send_string(int uart, char* command)
{
    printf("send: %s\n", command);
}

int main ()
{
    char str[] = "run arg1 arg2";
    int argc, i;

    argc = parse_command(str, args);

    for(i=0;i<argc; i++)
    {
        uart_send_string(1, args[i]);
    }

    return 0;
}

непонятно только, зачем отправлять команду в порт порциями?

да, спасибо. так работает. самый лучший ваиант - он к тому же разруливает множественные пробелы. в моем варианте я должен почистить пробелы в начале и в середине.

uint32_t PARSER_ParseCommandArguments(char *str, char *com, char arg[4][20])
{
    uint32_t char_idx = 0;
    uint32_t arg_idx = 0;
    //trim leading spaces
    while(*str++ == ' ');
      str--;
     while(*str)
    {
        if(*str != ' ')  //not space
        {
            if(arg_idx==0)  //command
            {
                com[char_idx++] = *str;
                com[char_idx] = 0;
                //*com++ = *str;
            }
            else  //arguments
            {
                arg[arg_idx-1][char_idx++] = *str;
                arg[arg_idx-1][char_idx] = 0;
            }
        }
        else    //space
        {
            char_idx = 0;
            arg_idx++;
            //to avoid multiple spaces
            while(*str++ == ' ');
              //str++; 
            str-=2;  
        }
        str++;
    }
    return arg_idx;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...