Преобразование массива символов в строку [и Pebble]

#c #arrays #string #pointers #pebble-watch

#c #массивы #строка #указатели #pebble-смотреть

Вопрос:

У меня есть массив символов, который я пытаюсь превратить в указатель символа на строку. Я полагаю, что это включает в себя получение указателя на первый элемент массива символов и добавление нулевого символа в конец массива символов. Причина этого в том, что я пытаюсь затем передать его в SimpleMenuItem для умных часов pebble, где .title должен получить char* , указывающий на строку.

Хотя я смог заполнить массив символов и (я думаю) добавил нулевой символ и получил указатель, я не могу увидеть заголовок на моем pebble. Я не уверен, является ли это проблемой pebble или проблемой моего понимания C, но я сильно чувствую, что это может быть первое.

Код Pebble (C):

 void in_received_handler(DictionaryIterator *received, void *context) {
    dataReceived = dict_read_first(received);
    APP_LOG(APP_LOG_LEVEL_DEBUG, "read first");

    while (dataReceived != NULL){

        if (dataReceived->key == 0x20) {

            //original is of the format "# random string", i.e. "4 test name"
            char* original = dataReceived->value->cstring;
            APP_LOG(APP_LOG_LEVEL_DEBUG, original);

            char originalArray[strlen(original)];
            //copy over to originalArray
            for (unsigned int i = 0; i < strlen(original); i  ) {
                originalArray[i] = original[i];
            }

            char* keysplit = strtok(originalArray, " ");
            APP_LOG(APP_LOG_LEVEL_DEBUG, keysplit);

            //key
            int key = atoi(keysplit);
            APP_LOG(APP_LOG_LEVEL_DEBUG, "Int Key: %d", key);

            //good until here
            char remainderArray[sizeof(originalArray)-strlen(keysplit)  1];

            //assign rest of string to new array
            for (unsigned int i = 1; i < sizeof(remainderArray)-1; i  ){
                APP_LOG(APP_LOG_LEVEL_DEBUG, "Character             : %c", originalArray[i strlen(keysplit)]);
                remainderArray[i] = originalArray[i strlen(keysplit)];
                APP_LOG(APP_LOG_LEVEL_DEBUG, "Character in new Array: %c", remainderArray[i]);
            }

            remainderArray[sizeof(remainderArray)-1] = '';

            //data is sucesfully placed into remainderArray
            char* ptr = remainderArray;
            strncpy(ptr, remainderArray, sizeof(remainderArray) 1);
            ptr[sizeof(remainderArray) 1] = '';

            chats[key] = (SimpleMenuItem){
                // You should give each menu item a title and callback
                .title = amp;remainderArray[0],
                .callback = selected_chat,
            };

        }

        dataReceived = dict_read_next(received);
        APP_LOG(APP_LOG_LEVEL_DEBUG, "read again");

    }

    layer_mark_dirty((Layer *)voice_chats);
}
  

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

Спасибо!

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

1. char remainderArray[...]; ... char* ptr = remainderArray; strncpy(ptr, remainderArray, sizeof(remainderArray) 1); это плохо. Код заполняется на remainderArray 1 больше своего размера.

Ответ №1:

(Я не знаю, что такое Pebble, поэтому этот ответ основан исключительно на языке C.)

Я думаю, что ваша главная проблема здесь:

 char* ptr = remainderArray;
strncpy(ptr, remainderArray, sizeof(remainderArray) 1);
  

Указатели источника и назначения одинаковы. Что вы пытаетесь здесь сделать?

Стандарт C (или его окончательный общедоступный проект) гласит:

7.24.2.4 Функция strncpy

2. strncpy Функция копирует не более n символов (символы, следующие за нулевым символом, не копируются) из массива, на который указывает s2 , в массив, на который указывает s1 308). Если копирование происходит между объектами, которые перекрываются, поведение не определено.

Если вам нужно скопировать перекрывающийся объект, вы должны использовать memmove() или скопировать символы самостоятельно в цикле.

Я также думаю, что в вашем коде есть несколько отдельных ошибок:

 char originalArray[strlen(original)];
  

Это не оставляет места для завершающего нулевого символа.

 ptr[sizeof(remainderArray) 1] = '';
  

При этом записывается один байт после конца remainderArray .

Ответ №2:

Решение на самом деле намного проще этого.

Во-первых, пожалуйста, обратите внимание, что массив символов и указатель на строку — это фактически одно и то же. Они оба являются указателями на адрес первого байта. В обоих случаях системные функции будут искать нулевой символ, чтобы определить конец строки (strlen, strcpy, printf и т.д.). char* и char[] взаимозаменяемы.

Когда вы получаете данные в свой in_received_handler() , указатель, который вы получаете ( dataReceived->value->cstring ), указывает на буфер приема Bluetooth, и вам нужно скопировать эту строку куда-нибудь еще. Таким образом, каждый раз, когда экран нужно перерисовывать, символы будут доступны.

Поскольку вы получаете динамическое количество элементов, вам необходимо динамически выделять память с помощью malloc() . Вам следует не забыть освободить эту память позже (с помощью free() ).

Это компилируется и должно делать то, что вы хотите:

 void in_received_handler(DictionaryIterator *received, void *context) {
  Tuple *dataReceived = dict_read_first(received);

  while (dataReceived != NULL){
    if (dataReceived->key == 0x20) {
      //original is of the format "# random string", i.e. "4 test name"
      char* original = dataReceived->value->cstring;
      APP_LOG(APP_LOG_LEVEL_DEBUG, original);

      char* keysplit = strtok(original, " ");
      APP_LOG(APP_LOG_LEVEL_DEBUG, keysplit);

      //key
      int key = atoi(keysplit);
      APP_LOG(APP_LOG_LEVEL_DEBUG, "Int Key: %d", key);

      // This will return the second part of the string.
      char *message = strtok(NULL, " ");
      // Allocate some memory to hold a copy of that message
      char *copyOfMessage = malloc(strlen(message));
      // And copy the message from the bluetooth buffer to the new memory
      strcpy(copyOfMessage, message);
      APP_LOG(APP_LOG_LEVEL_DEBUG, "Message: %d", key);

      chats[key] = (SimpleMenuItem){
        // You should give each menu item a title and callback
        .title = copyOfMessage,
        .callback = selected_chat,
      };
    }

    dataReceived = dict_read_next(received);
  }
  layer_mark_dirty((Layer *)voice_chats);
}
  

Кстати, вместо того, чтобы использовать одну строку с ключом и сообщением и анализировать ее на C в клиенте, я бы рекомендовал использовать другой индекс ключа сообщения приложения для передачи вашего «ключа». Например, вы могли бы иметь:

 {
  0x1: 33,                 // the key
  0x20: "message"           // the actual message
}