Проблемы с записью в 2-мерные массивы, встроенный C

#c #embedded

#c #встроенное

Вопрос:

У меня проблемы с пониманием того, что происходит с моим кодом, в основном в отношении 2D-массивов. Я пытаюсь использовать функцию в моем файле связи для декодирования командной строки с терминала. Я хочу, чтобы он разбил строку и вывел ответы, обновив глобальные буферы. У меня возникли проблемы с записью в эти массивы, и я не понимаю, почему. В приведенном ниже коде я просто присвоил значение массиву символов USART1_Command, где в реальной программе оно поступает из терминала.

Main и объявления:

 //Global declarations//
#define USART1_BUFFER_SIZE (100)
#define MAX_COMMAND_INT_VALUES (50)
#define MAX_COMMAND_STR_VALUES (50)
#define MAX_COMMAND_STR_LENGTH (50)
char USART1_Buffer[USART1_BUFFER_SIZE];
uint16_t USART1_Write_Index = 0;
char USART1_Command[MAX_COMMAND_STR_LENGTH] = {0x00};
uint16_t USART1_Command_Int_Values[MAX_COMMAND_INT_VALUES] = {0x00};
char **USART1_Command_Str_Values;

void main(void){
  USART1_Command_Str_Values = (char **)calloc(MAX_COMMAND_STR_VALUES, sizeof(char *));
  uint16_t i = 0;
  for(i = 0; i < MAX_COMMAND_INT_VALUES; i  ){
    USART1_Command_Str_Values[i] = (char *)calloc(MAX_COMMAND_STR_LENGTH, sizeof(char));
  }

  strcpy(USART1_Command, "TESTCOMMAND,45,36,21-TEST1-TEST2");
  USART1_Command_Decode(USART1_Command, USART1_Command_Int_Values, USART1_Command_Str_Values, MAX_COMMAND_INT_VALUES, MAX_COMMAND_STR_VALUES, MAX_COMMAND_STR_LENGTH);

  while(1){

  }
}
  

и функция:

 void USART1_Command_Decode(char *command, uint16_t *int_values_buffer, char **str_values_buffer, uint16_t int_values_buffer_size, uint16_t str_values_buffer_size, uint16_t str_values_size){
  uint16_t i = 0;
  uint16_t j = 0;
  uint16_t length = strlen(command);
  
  int16_t Int_Values_Index = -1;
  bool Int_Value_Flag = false;

  char **Int_Values;
  Int_Values = (char**)calloc(int_values_buffer_size, sizeof(char*));
  for(i = 0; i < int_values_buffer_size; i  ){
    Int_Values[i] = (char*)calloc(str_values_size, sizeof(char));
  }

  const uint16_t Max_Str_Values = 50;
  int16_t Str_Values_Index = -1;
  bool Str_Value_Flag = false;
  
  for(i = 0; i < length; i  ){

     switch(command[i]){

        case ',': //Signifies integer value//
            if(Int_Values_Index < int_values_buffer_size){
                Int_Values_Index  ;
                Int_Value_Flag = true;
                Str_Value_Flag = false;
                j = 0;
            }
            command[i] = 0x00;
            break;

        case '-': //Signifies string value//
            if(Str_Values_Index < str_values_buffer_size){
                Str_Values_Index  ;
                Str_Value_Flag = true;
                Int_Value_Flag = false;
                j = 0;
            }
            command[i] = 0x00;
            break;

        default:
            if(Int_Value_Flag){
                Int_Values[Int_Values_Index][j] = command[i];
                command[i] = 0x00;
                j  ;
            }
            if(Str_Value_Flag){
                str_values_buffer[Str_Values_Index][j] = command[i];
                command[i] = 0x00;
                j  ;
            }
            break;
     }
  }

  //Convert integer strings to integers//
  for(i = 1; i <= Int_Values_Index; i  ){
      int_values_buffer[i] = atoi(Int_Values[i]);
  }


  for(i = 0; i < int_values_buffer_size; i  ){
    free(Int_Values[i]);
  }

  free(Int_Values);
}
  

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

1. Какие проблемы вы испытываете?

2. если это код микроконтроллера, забудьте о malloc, calloc и такого рода динамическом распределении

3. Устройство представляет собой STM32L432KC, запрограммированное через ST-Link с использованием crosstudio 4.7. Проблема, с которой я сталкиваюсь, заключается в том, что 2D динамические массивы в функции не принимают значения. Значения присутствуют в массиве USART1_Command, но 2D-массивы после присвоений по-прежнему равны нулю. Я хочу, чтобы все целочисленные значения были разделены и помещены в USART1_Command_Int_Values, значения char[] после символа ‘-‘ должны входить в USART1_Command_Str_Values, а все перед первым ‘,’ должно оставаться в USART1_Command

4. Примечание: здесь нет 2D-массивов. С Int_Values[Int_Values_Index][j] , Int_Values[Int_Values_Index] является указателем.

5. @progroober Как я уже писал, забудьте о malloc и calloc. Они бесполезны при разработке uC. Обычно куча имеет значение около 512 байт, и она фрагментируется буквально мгновенно. программирование UCS вам нужно использовать большую часть функций C, которые вы используете при программировании больших компьютеров

Ответ №1:

Я понял это, способ, которым я смог заставить его работать, заключался в следующем:

Объявление глобальных переменных:

 #define MAX_COMMAND_INT_VALUES (50)
#define MAX_COMMAND_STR_VALUES (50)
#define MAX_COMMAND_STR_LENGTH (50)
char USART1_Command[MAX_COMMAND_STR_LENGTH] = {0x00};
uint16_t USART1_Command_Int_Values[MAX_COMMAND_INT_VALUES] = {0x00};
char USART1_Command_Str_Values[MAX_COMMAND_STR_VALUES][MAX_COMMAND_STR_LENGTH];
  

Функция:

 void USART1_Command_Decode(char *command, uint16_t *int_values_buffer, uint16_t int_values_buffer_size, uint16_t str_values_buffer_size, uint16_t str_values_size, char str_values_buffer[str_values_buffer_size][str_values_size]){
  uint16_t i = 0;
  uint16_t j = 0;
  uint16_t length = strlen(command);
  
  int16_t Int_Values_Index = -1;
  bool Int_Value_Flag = false;

  char Int_Values[int_values_buffer_size][str_values_size];
  
  for(i = 0; i < int_values_buffer_size; i  ){
    for(j = 0; j < str_values_size; j  ){
      Int_Values[i][j] = 0x00;
    }
  }

  int16_t Str_Values_Index = -1;
  bool Str_Value_Flag = false;
  
  for(i = 0; i < length; i  ){

     switch(command[i]){

        case ',': //Signifies integer value//
            if(Int_Values_Index < int_values_buffer_size){
                Int_Values_Index  ;
                Int_Value_Flag = true;
                Str_Value_Flag = false;
                j = 0;
            }
            command[i] = 0x00;
            break;

        case '-': //Signifies string value//
            if(Str_Values_Index < str_values_buffer_size){
                Str_Values_Index  ;
                Str_Value_Flag = true;
                Int_Value_Flag = false;
                j = 0;
            }
            command[i] = 0x00;
            break;

        default:
            if(Int_Value_Flag){
                Int_Values[Int_Values_Index][j] = command[i];
                command[i] = 0x00;
                j  ;
            }
            if(Str_Value_Flag){
                str_values_buffer[Str_Values_Index][j] = command[i];
                command[i] = 0x00;
                j  ;
            }
            break;
     }
  }

  //Convert integer strings to integers//
  for(i = 0; i <= Int_Values_Index; i  ){
      int_values_buffer[i] = atoi(Int_Values[i]);
  }

}
  

Вызов функции:

 USART1_Command_Decode(USART1_Command, USART1_Command_Int_Values, MAX_COMMAND_INT_VALUES, MAX_COMMAND_STR_VALUES, MAX_COMMAND_STR_LENGTH, USART1_Command_Str_Values);
  

Спасибо @P__J__ за помощь!

РЕДАКТИРОВАТЬ: я обнаружил основную проблему с моим исходным кодом, у меня были проблемы с переполнением стека, потому что я неправильно понимал распределение стека и кучи в Cross Studio. У меня было 256 байт стека, когда я думал, что у меня больше 20 КБ. Я выделил 16 КБ для стека и 8 КБ для кучи, все проблемы с malloc() и calloc() исчезли вместе с проблемами записи массива. Я прошу прощения у всех за ненужный вопрос.

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

1. Вместо for (i = 0; i < int_values_buffer_size; i ) { for (j = 0; j < str_values_size; j ) { Int_Values[i][j] = 0x00; } } этого можно упростить с memset(Int_Values, 0, sizeof Int_Values);

2. Вы действительно не хотите выделять 50×50 байт в стеке, поверьте мне. Переместите этот массив в статическое хранилище. Кроме того, очистка всего этого фрагмента при каждом вызове функции является огромным временным узким местом, просто следите за используемым размером.

3. Здесь тоже много других проблем. Как только вы все заработаете, я бы рекомендовал опубликовать полный рабочий код по адресу codereview.stackexchange.com

4. @Lundin Я был бы рад это сделать, и я ценю этот отзыв, потому что я относительно новичок в программировании на C, и у меня примерно такой же опыт работы со встроенным C. Я пытаюсь написать общий файл, который я могу использовать для команд через последовательный терминал в любом проекте, прямо сейчас я использую его для управления некоторыми светодиодными нитями WS2811 и WS2812B. Это тоже все хобби, поэтому проблем с интеллектуальными правами или чем-то в этом роде не будет