#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
}