реклама на сайте
подробности

 
 
> указатель на указатель, помочь разобраться
Метценгерштейн
сообщение Jul 27 2018, 10:48
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Встретил в коде следующую конструкцию:

Код
ble_advdata_tk_value_t* oob_key;
err_code = nfc_tk_value_get(&oob_key);


где:

Код
typedef struct
{
  uint8_t tk[BLE_GAP_SEC_KEY_LEN];      /**< Array containing TK value in little-endian format. */
} ble_advdata_tk_value_t;


Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value)
{
    if (m_tag_match)
    {
        *pp_tk_value = &m_device_tk;
        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_NOT_FOUND;
    }
}


Есть вопрос. Как все проговорить что тут происходит?
Есть тип структуры ble_advdata_tk_value_t. Создали переменную- указатель на этот тип: oob_key.
Дальше? Передаем не просто адрес (сам указатель oob_key), а именно адрес этого указателя? А в ф-ии уже принимаем указатель на указатель?
Разыменовывали на один уровень вверх и по тому значению присвоили адрес уже массива.

А проще никак?
err_code = nfc_tk_value_get(oob_key);

и приняли:
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value)
{
    if (m_tag_match)
    {
        pp_tk_value = &m_device_tk;
        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_NOT_FOUND;
    }
}
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 27)
Kabdim
сообщение Jul 27 2018, 11:05
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Всё что со знаками вопроса - верно. Проще никак. Смысл указателя на указатель, что бы вернуть значение не копируя содержимое в буфер-аргумента.
Последний кусок кода напрочь ошибочный. "pp_tk_value = &m_device_tk;" скопирует указатель в аргумент. Но при выходе из функции oob_key не поменяется.
Go to the top of the page
 
+Quote Post
x893
сообщение Jul 27 2018, 11:44
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



есть передать сам указатель вы его изменить не сможете.
у них если if (m_tag_match) то указатель меняется.
Всё правильно сделано (согласно их логике).
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 11:51
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Хорошо, а в моем приведенном примере- в чем ошибка? Не могу указателю сразу адрес присвоить разве?
Go to the top of the page
 
+Quote Post
x893
сообщение Jul 27 2018, 12:09
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Цитата(Метценгерштейн @ Jul 27 2018, 14:51) *
Хорошо, а в моем приведенном примере- в чем ошибка? Не могу указателю сразу адрес присвоить разве?

Присвоить можете, только указатель

ble_advdata_tk_value_t* oob_key;

не изменится.

P.S. Может книжечку почитать ?
"Стань профи С за 24 часа"
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 12:25
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Не нашел в инете такой книжки.

Не совсем понимаю, зачем мне менять указатель. Точнее, я же в их логике его и меняю через разыменование и записи по нему.
Go to the top of the page
 
+Quote Post
_pv
сообщение Jul 27 2018, 12:39
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954



на что будет указывать oob_key после выполнения функции в первом случае, и во втором?
ну или даже так: что произойдёт с переменной pp_tk_value после выхода из функции?

Цитата(Метценгерштейн @ Jul 27 2018, 19:25) *
Точнее, я же в их логике его и меняю через разыменование и записи по нему.

pp_tk_value = &m_device_tk;
где именно в данной строчке происходит разыменование указателя?
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 12:54
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Разыменование происходит в оригинальном примере:
*pp_tk_value = &m_device_tk;

В моем случае, и в приведенном вами примере, конечно, разыменования не происходит. Просто идет присвоение адреса переменной типа указатель:
pp_tk_value = &m_device_tk;

Попробую ответить на первый вопрос.
После выполнения ф-ии oob_key будет указывать в первом случае на
&m_device_tk
т.к. происходит разыменование и присвоение адреса:
*pp_tk_value = &m_device_tk;

В моем случае- на то же. Понимаю, что где-то не прав, но не доходит почему.

pp_tk_value уйдет из области видимости и останется в записи oob_key. Все изменения будут внесены в oob_key .
Go to the top of the page
 
+Quote Post
_pv
сообщение Jul 27 2018, 13:49
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954



Цитата(Метценгерштейн @ Jul 27 2018, 19:54) *
В моем случае- на то же. Понимаю, что где-то не прав, но не доходит почему.
pp_tk_value уйдет из области видимости и останется в записи oob_key. Все изменения будут внесены в oob_key .

pp_tk_value это просто ещё один указатель, который указывает на то же на что и oob_key.
точнее указывал, а потом стал указывать на &m_device_tk.

в каком именно месте в вашем коде происходит запись в oob_key?
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 14:32
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Цитата(_pv @ Jul 27 2018, 16:49) *
в каком именно месте в вашем коде происходит запись в oob_key?


*pp_tk_value = &m_device_tk;
в этом месте, т.к. работаю с указателями по памяти, а не по значению.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Jul 27 2018, 14:48
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(Метценгерштейн @ Jul 27 2018, 15:54) *
Понимаю, что где-то не прав, но не доходит почему.

Недостаток базовых знаний, вам совершенно не зря советуют книжки почитать. На уровне ассемблера при вызове функции все аргументы копируются в контекст функции. В самой функнции эти копии-аргументы можно менять как заблагорассудится, на источник своих значений они уже повлиять не могу. Поэтому и существуют указатели, что передать(скопировать) в функцию значение адреса объекта, который нужно изменить. Если бы вы программировали на с++, то вы могли бы(но делать так не стоит использовать ссылку для того что бы ваш пример заработал:
Цитата
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t *& pp_tk_value)

И тогда по ссылке изменения вернуться в oob_key. Но делать так, повторюсь, не надо. Нужно понять для чего нужны указатели и указатель на указатель.
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 14:50
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Так я же не против почитать что-то) Читал много, но с этим вопросом не сталкивался. Если есть под рукой статья, где это все наглядно демонстрируется, то с удовольствием посмотрю.
Ну а в чем я в предыдущем посте не прав?

*pp_tk_value = &m_device_tk;
в этом месте, т.к. работаю с указателями по памяти, а не по значению.

Это тоже самое что вы и сказали:
На уровне ассемблера при вызове функции все аргументы копируются в контекст функции. В самой функнции эти копии-аргументы можно менять как заблагорассудится, на источник своих значений они уже повлиять не могу. Поэтому и существуют указатели, что передать(скопировать) в функцию значение адреса объекта, который нужно изменить.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Jul 27 2018, 15:02
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Упрощенно:
Переменная снаружи имеет какое-то значение
Выполняется вызов
В стеке аллокируется кадр под все аргументы
В эти новые места копируется значения переменных (связь между аргументами в функции и теми переменными что были использованы для вызова снаружи оборвалась)
В функции меняются аргументы как угодно, они находятся в том кадре что был сделан при вызове.
Возврат из функции (кадр аргументов освобождается, значения которые там находились становятся мусором)

Цитата(Метценгерштейн @ Jul 27 2018, 17:50) *
*pp_tk_value = &m_device_tk;

Если ble_advdata_tk_value_t * pp_tk_value , в этом коде вы просто испортили начало массива pp_tk_value каким-то левым для содержимого этого массива адресом.
Go to the top of the page
 
+Quote Post
DASM
сообщение Jul 27 2018, 15:22
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(Kabdim @ Jul 27 2018, 17:48) *
Но делать так, повторюсь, не надо.
Почему?
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 15:24
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value)
{
    if (m_tag_match)
    {
        *pp_tk_value = &m_device_tk;
        return NRF_SUCCESS;
    }
    else
    {
        return NRF_ERROR_NOT_FOUND;
    }
}

Это код из оригинального примера.
Произошло разыменование указателя и записался адрес чего- то. Но, если бы на вход пришел адрес массива, то да. А посмотрите внимательно- пришел адрес адреса))

Упрощенно:
Переменная снаружи имеет какое-то значение
Выполняется вызов
В стеке аллокируется кадр под все аргументы
В эти новые места копируется значения переменных (связь между аргументами в функции и теми переменными что были использованы для вызова снаружи оборвалась)
В функции меняются аргументы как угодно, они находятся в том кадре что был сделан при вызове.
Возврат из функции (кадр аргументов освобождается, значения которые там находились становятся мусором)


Полностью согласен. Эти вещи я знаю отлично. Это не тот вопрос, который мне не понятен. Для того и передают в ф-ю адрес переменной. Изменив ее там, она поменяется и там откуда ее переслали.
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Jul 27 2018, 15:41
Сообщение #16


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Попробую внести ясности-понятности.
Код
// допустим, Data разместилась по адресу 0x5000
// значение по адресу 0x5000 после присвоения будет равно 10
int Data = 10;

// допустим, pData разместилась по адресу 0x10000
// значение по адресу 0x10000 после присвоения будет равно 0x5000 (адрес Data)
int *pData = &Data;

// чтобы работать на чтение/запись с содержимым Data через pData, используем операцию разыменовывания
int a = *pData; // a == 10
*pData = 20;   // теперь Data == 20

// допустим, ppData разместилась по адресу 0x20000
// значение по адресу 0x20000 после присвоения будет равно 0x10000 (адрес pData)
int **ppData = &pData;

// чтобы работать на чтение/запись с содержимым pData через ppData, используем операцию разыменовывания
int *a = *ppData; // a == 0x10000
// чтобы получить доступ к переменной Data, используется двойное разыменовывание
int b = **ppData; // b == 20

У меня, например, двойной уровень косвенного обращения (указатель на указатель) используется в кольцевом буфере.
Имеется автомат, который расшифровывает принимаемые символы от фреймера (байт-стаффинг) по UART и складывает их в кольцевой буфер. Когда фрейм данных полностью принят, нужно как-то сообщить пользователю о размере принятого сообщения. Поэтому, перед тем, как я складирую принимаемые символы в кольцевой буфер, я резервирую в нем один байт для записи в него размера посылки после того, как весь фрейм будет принят. Чтобы не городить лишних телодвижений, я использую что-то наподобие вот такой конструкции:
Код
char *pMessageSize; // адрес элемента в кольцевом буфере, содержащий информацию о размере принятого сообщения

...

RingBufferReserveByte(&pMessageSize); // прототип RingBufferReserveByte(char **Address)

...

// после приема всей посылки прямой записью в память добавил в заранее зарезервированное место в кольцевом буфере информацию о размере сообщения, не думая по положениях head- и tail-указателей буфера
*pMessageSize = ByteCounter;

// ну а тут уже можно выдать семафор в основную программу, где она считывает первый элемент - видит размер сообщения - считывает его, перемещает позицию следующего чтения и, (если там еще что-то уже успело придти) двигается так дальше
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Jul 27 2018, 15:42
Сообщение #17


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



2Метценгерштейн: Видимо я утерял нить рассуждений. rolleyes.gif
Цитата(DASM @ Jul 27 2018, 18:22) *
Почему?

Соглашения по стилю обычно это определяют. Что по ссылке передаются данные которые долго копировать, но не нужно менять, а по указателям можно делать что угодно и это хорошо будет видно в коде благодаря звездочке/стрелке.
Go to the top of the page
 
+Quote Post
Herz
сообщение Jul 27 2018, 17:32
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(Kabdim @ Jul 27 2018, 18:02) *
В стеке аллокируется кадр под все аргументы

Простите, что делается? 05.gif
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Jul 27 2018, 18:21
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(Herz @ Jul 27 2018, 20:32) *
Простите, что делается? 05.gif

Выделяется (англ. allocate).
Но что там куда выделяется зависит еще все-таки от соглашения вызовов используемого компилятора.
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 27 2018, 19:42
Сообщение #20


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Arlleex, спасибо за подробное изложение. Прошлись по основам. Подвели все к общему знаменателю.
Могли бы в том же духе первый пост разложить? Именно оригинальный пример из кода.
Go to the top of the page
 
+Quote Post
x893
сообщение Jul 27 2018, 19:46
Сообщение #21


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Для АРМ параметры передаются через регистры (пока хватает). Так что Ваши параметры после выхода просто пропадут. Проще посмотреть отладчиком, если лень книги читать.
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Jul 28 2018, 11:15
Сообщение #22


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(Метценгерштейн @ Jul 27 2018, 22:42) *
Могли бы в том же духе первый пост разложить? Именно оригинальный пример из кода.

Ну, попробую.
Код
// определение типа данных ble_advdata_tk_value_t
typedef struct
{
  uint8_t tk[BLE_GAP_SEC_KEY_LEN];
}ble_advdata_tk_value_t;


Код
// oob_key - указатель на любой объект в памяти, имеющий тип ble_advdata_tk_value_t
ble_advdata_tk_value_t *oob_key;

Допустим, для общего случая, что oob_key разместился по адресу 0x1000 и был объявлен в функции, поэтому без явной инициализации в нем будет лежать мусор. Значит по адресу 0x1000 сейчас лежит мусор.

В вызове
Код
err_code = nfc_tk_value_get(oob_key); // прототип ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t *pp_tk_value)

мы передаем копию значения oob_key (на данный момент мусор) в функцию nfc_tk_value_get(), а это значит, что, во-первых, в функцию передался мусор, а во-вторых, функция не сможет изменить значение по адресу 0x1000 (значение oob_key), поскольку она не знает адрес oob_key.
Поэтому повышается уровень косвенного обращения вызовом
Код
err_code = nfc_tk_value_get(&oob_key); // прототип ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t **pp_tk_value)

Здесь уже функции передается число 0x1000, и эта функция может что угодно делать с этим числом (это адрес oob_key) - например, инициализировать его адресом динамически созданного объекта типа ble_advdata_tk_value_t. В Вашем случае
Код
*pp_tk_value = &m_device_tk; // записать по адресу 0x1000 (то есть в ячейку oob_key) адрес объекта m_device_tk типа ble_advdata_tk_value_t


Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 28 2018, 16:59
Сообщение #23


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Спасибо. Упустил из вида момент, что
Код
ble_advdata_tk_value_t *oob_key;

это просто объявление переменной, но она непроинициализирована. А здесь
Код
err_code = nfc_tk_value_get(&oob_key);

мы просто передаем адрес (0х1000) этой переменной. Как обычно.
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Jul 29 2018, 05:19
Сообщение #24


Профессионал
*****

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Спасибо. Упустил из вида момент, что
Код
ble_advdata_tk_value_t *oob_key;

это просто объявление переменной, но она непроинициализирована. А здесь
Код
err_code = nfc_tk_value_get(&oob_key);

мы просто передаем адрес (0х1000) этой переменной. Как обычно.

а вот здесь зачем указатель на указатель?
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value)

Разве не достаточно было так:
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value)
{
    pp_tk_value = &m_device_tk;
}


Давайте аналогию приведем.

int a;
int *p;
p = &a;
Go to the top of the page
 
+Quote Post
andrew_b
сообщение Jul 29 2018, 07:27
Сообщение #25


Профессионал
*****

Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757



Цитата(Метценгерштейн @ Jul 29 2018, 08:19) *
Давайте аналогию приведем.

int a;
int *p;
p = &a;

Давйте.
Код
int a;
int *p;
p = &a;
Это "снаружи" функции.
В самой функции параметр (например, p1) является копией p. Изменяя p1, вы не можете изменить p.
Код
   /* При вызове функции происходит следующее */
   int *p1 = p; /* в параметр копируется указатель, передаваемый в функцию */
  
   int b; /* локальная переменная функции */
   p1 = &b; /* изменяется p1, т.е копия p, но сам p не изменяется */
Go to the top of the page
 
+Quote Post
GeorgK
сообщение Aug 31 2018, 17:37
Сообщение #26





Группа: Участник
Сообщений: 9
Регистрация: 23-08-18
Пользователь №: 107 025



Возможно (вроде этого не было), стоит ещё упомянуть о передаче аргумента в функцию по адресу?

Код
void func(int &k) { k = 5};

....

int k = 0;
func(k);
//Здесь k равно 5.


Иногда это удобнее, если только не забывать, что изменение аргумента скажется на вызывающей функции.

Впрочем, для передачи сложных типов часто используется запись вроде func(const int &arg),
позволяющая не тащить при вызове в стек весь тип, а обойтись его адресом. А компилятор проследит, чтобы по ходу функции аргумент не был изменён.
Go to the top of the page
 
+Quote Post
DASM
сообщение Sep 1 2018, 04:17
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Давайте давайте учтите плохому.
"Within function parameter lists all references must be const:

void Foo(const string &in, string *out);
In fact it is a very strong convention in Googlecode that input arguments are values or const references while output arguments
are pointers." https://google.github.io/styleguide/cppguid...tput_Parameters
И это абсолютно правильно, делать ф-цию, вызов которой семантически выглядит как принимающая параметр по значении, а на деле давать ей неконстантную ссылку - форменное свинство
Go to the top of the page
 
+Quote Post
Professor Chaos
сообщение Sep 1 2018, 13:53
Сообщение #28


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 25-08-17
Пользователь №: 98 970



Цитата(Метценгерштейн @ Jul 29 2018, 08:19) *
а вот здесь зачем указатель на указатель?
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value)

Разве не достаточно было так:
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value)
{
    pp_tk_value = &m_device_tk;
}

Вам надо понять (один раз и на всю жизнь), для чего в качестве аргумента функции передавать указатель на указатель.
Поймёте это - поймёте и ваш код.

То, что вы знаете, и о чём пишется в любом учебнике по С
1.Передавая объекты в функцию по-значению, вы сможете использовать их (значения), но не сможете их изменить. Все изменения аргументов внутри функции изменят лишь копии объектов, переданных в функцию, но не сами объекты. Т.е. изменение копии никак не отражается на оригинале, с которого копия была снята.
2. Чтобы можно было изменять значения объекта изнутри функции, в функцию в качестве аргумента надо передать не сам объект, а указатель на него. В этом случае в функцию передастся копия указателя на объект. Но т.к. копия указателя на объект указывает на тот же самый объект, что и исходный указатель, то этом случае функция через косвенную адресацию будет иметь доступ к такому объекту. Ведь в качестве параметра ей придёт указатель (т.е. фактически адрес) объекта. Зная адрес объекта (т.е. имея копию указателя на него) всегда можно изменить и сам объект, разыменовав указатель и присвоив ему новое значение.

А теперь то, что из этого следует, но на чём не акцентируется внимание в учебниках или вообще не говорится.
3. А что делать, если вам надо внутри функции изменить значение объекта имеющего тип указателя? Т.е. надо внутри функции присвоить указателю адрес другого объекта. Как такое сделать? Если передать в функцию сам указатель, то можно будет изменять тот объект, на который он указывает, но не сам указатель. А нам то этого не надо. Нам надо, чтобы указатель после выхода из функции указывал на другой объект (содержал его адрес). Вот для этого и приходится передавать в качестве аргументов функциям указатель на указатель.

Очень простой пример для иллюстрации сказанного в п. 3
Код
// Произвольный тип данных пользователя (предположим, int)
typedef int usertype_t;

// Функция, изменяющая значение указателя на объект типа usertype_t
// PtrToPtrToObj -указатель на указатель на объект типа usertype_t
// PtrToNewObj - указатель на новый объект
void SetPtrToNewObj (usertype_t** PtrToPtrToObj, usertype_t* PtrToNewObj) {
  *PtrToPtrToObj=PtrToNewObj;
}

int main (){    
    // Объекты типа usertype_t
  usertype_t ObjA, ObjB;
  
  // Указатель на объект типа usertype_t
  usertype_t* ObjPtr=&ObjA;       // Теперь ObjPtr указывает на объект ObjA
  
  // Меняем значение указателя. Нам нужно, чтобы он теперь указывал на другой объект
  // Эквивалент строки: ObjPtr=&ObjB;
  SetPtrToNewObj (&ObjPtr,&ObjB); // Теперь ObjPtr указывает на объект ObjB
}


А теперь зная это посмотрим на код:
Код
ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value)
{
    pp_tk_value = &m_device_tk;
}

Что он делает?
pp_tk_value - это аргумент функции. Т.е. при вызове функции в него копируется значение типа ble_advdata_tk_value_t *. Т.е. это копия указателя на объект типа ble_advdata_tk_value_t. КОПИЯ указателя, а не сам указатель!
pp_tk_value = &m_device_tk; - что вы сделали этой строкой?
Вы присвоили КОПИИ УКАЗАТЕЛЯ новое значение. Но изменение КОПИИ никак не повлияло на оригинал. Оригинальный указатель остался прежним. А после выхода из функции pp_tk_value вышел из области видимости. Т.е. эта строка не изменила никаких объектов программы.
А должна была присвоить указателю новое значение - адрес объекта m_device_tk типа ble_advdata_tk_value_t.

Сообщение отредактировал Professor Chaos - Sep 1 2018, 15:08
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 10:01
Рейтинг@Mail.ru


Страница сгенерированна за 0.01626 секунд с 7
ELECTRONIX ©2004-2016