Приведение char ** к char * - Это меняет то, на что оно указывает? - PullRequest
0 голосов
/ 08 октября 2018

Если у меня есть указатель на массив char * s, другими словами, char ** с именем p1, что я получу, если сделаю (char *) p1?Я предполагаю, что будет некоторая потеря точности.Какую информацию я бы потерял, и на что теперь будет указывать p1?Спасибо!

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

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

Так что char ** - это адрес памяти, который указывает, адрес памяти, который указываетto, символ.

0x0020 -> 0x0010 -> 0x0041 'A'

Когда вы разыгрываете, вы изменяете интерпретацию данных, а не фактические данные.Таким образом, char * равен

0x0020 -> 0x0010 (unprintable)

Это почти наверняка бесполезно.Интерпретация этих случайных данных как строки с нулевым символом в конце может привести к катастрофическим последствиям.

0 голосов
/ 08 октября 2018

Если бы вы спросили о преобразовании int ** в int *, ответ был бы другим.Давайте сначала рассмотрим это, потому что я подозреваю, что он более репрезентативен для вопроса, который вы намеревались задать, и дело char * более сложное, потому что в этом есть особая цель.

Предположим, у вас есть несколько int: int a, b, c, d;.Вы можете сделать массив указателей на них: int *p[] = { &a, &b, &c, &d };.Вы также можете сделать указатель на один из следующих указателей: int **q = &p[1];.Теперь q указывает на p[1], который содержит адрес b.

Когда вы пишете *q, компилятор знает, что q указывает на указатель на int, поэтомузнает *q указывает на int.Если вы напишите **q, компилятор, зная, что *q указывает на int, получит *q из памяти и использует его в качестве адреса для получения int.

Что происходитесли вы конвертируете q в int * и пытаетесь использовать его, как в printf("%d\n", * (int *) q);?Когда вы конвертируете q в int *, вы (ложно) говорите компилятору рассматривать его как указатель на int.Затем * (int *) q говорит компилятору перейти по этому адресу и получить int.

Это неверный код - его поведение не определено стандартом C.В частности, он нарушает C 2018 6.5 7, в котором говорится, что доступ к объекту должен иметь только выражение lvalue правильного типа - либо тип, совместимый с типом фактического объекта, либо некоторые другие случаи, ни один из которых здесь не применим.В точке q указывает указатель на int, но вы пытались получить к нему доступ, как если бы это был int, а это недопустимо.

Теперь давайте рассмотрим char ** до char * чехол.Как и раньше, вы можете взять char **q и преобразовать его в char *.Теперь вы говорите компилятору перейти в точку q, где есть указатель на char, и получить доступ к этой области памяти, как если бы там было char.

C имеет специальные правила для этого случая.Вам разрешено проверять байты, составляющие объекты, путем доступа к ним через char *.Итак, если вы преобразуете char ** в char * и используете его, как в * (char *) q, результатом будет первый (адрес с наименьшим адресом) байт, который составляет указатель там.Вы даже можете посмотреть на остальные байты, используя такой код:

char *t = (char *) q;
printf("%d\n", t[0]);
printf("%d\n", t[1]);
printf("%d\n", t[2]);
printf("%d\n", t[3]);

Этот код покажет вам десятичные значения для первых четырех байтов, которые составляют указатель на char, который находится наместоположение, указанное q.

В итоге, преобразование char ** в char * позволит вам исследовать байты, представляющие char *.Однако в общем случае не следует преобразовывать указатели одного уровня косвенности в указатели другого уровня косвенности.

...