Назначение указателя на массив указателей на символ - PullRequest
4 голосов
/ 21 августа 2010

gcc 4.4.4 c89

#define SIZE 5
    char *names[SIZE] = {"peter", "lisa", "simon", "sarah", "julie"};
    char *search_names[SIZE] = {0};
    size_t i = 0;

    for(i = 0; i < SIZE; i++ ) {
        search_names[i] = names[i]++;
    }

    for(i = 0; i < SIZE; i++) {
        printf("name to search for [ %s ]\n", search_names[i]);
    }

Я запутался в этой строке search_names[i] = names[i]++;, которая представляет собой массив указателей на char *.Просто мои эксперименты я думал, что это должно быть &names[i]++.Потому что я хочу получить указатель на это место.Таким образом, наличие & даст мне адрес, на который указывает указатель.

Полагаю, я мог бы увеличить и так: (names[i]) + i;

Просто запутался в этой строке.

Ответы [ 3 ]

7 голосов
/ 21 августа 2010

names[i] - указатель типа char*. &names[i] является указателем на names[i] и, следовательно, имеет тип char**. Картинка памяти:

names                    for each i, this is where names[i] *points*
|__________________          0     1    2     3     4
|                  |         |     |    |     |     |
|                  |         v     v    v     v     v
[0 ][1 ][2 ][3 ][4 ]  <gap>  peter0lisa0simon0sarah0julie0
        ^
        |_This is where &names[2] points, i.e. this is where names[2] *is*

name - это массив из 5 указателей, и я изобразил каждый указатель в квадратных скобках и его индекс. Плюс пробел, потому что указатели на моей машине 4 байта. Это ситуация сразу после инициализации names. Отдельный фрагмент памяти справа представляет собой последовательность байтов, где каждый 0 указывает байт 0 / NUL, а не символ 0. Реализация (компилятор, компоновщик и загрузчик работают вместе) является обязанностью назначать память для строковых литералов - я предположил, что все строковые литералы, которые вы использовали, будут кластеризованы вместе, хотя это не обязательно так. Наконец, числа 0 ... 4 указывают, куда указывает каждый указатель в names.

Поскольку вы присваиваете char*, вам нужен char*. Или, если посмотреть по-другому, указатели указывают на одно и то же, если (и только если) сами указатели имеют одинаковое значение. Так что, если вы хотите, чтобы search_names[i] (который является указателем) указывал на то же самое, на что указывает names[i], то search_names[i] = names[i] совершенно верно.

Хотя я не знаю, что намеревался сделать names[i]++. Изменяет указатель names[i]. Изменение указателя заставляет его указывать на другое. В этом случае вы получите names[0], указывающее на «eter», names[1], указывающее на «isa», и т. Д.

Вот как выглядит память после увеличения каждого указателя в names:

names                
|_____________           0     1    2     3     4
|             |          |     |    |     |     |
v             v          v     v    v     v     v
[0][1][2][3][4]         peter0lisa0simon0sarah0julie0

Кстати, вам разрешено назначать строковый литерал для char*, но это не значит, что вы должны . Было бы лучше объявить ваши массивы const char *names[SIZE]. Это неопределенное поведение для изменения памяти, выделенной компилятором для строкового литерала, и использование const char* вместо char* помогает обеспечить это.

2 голосов
/ 21 августа 2010

names [] определяется как массив указателей на символы.Следовательно, names [i] - это указатель на i-ю строку, содержащуюся в именах.search_names [] также является массивом указателей на char и, следовательно, search_names [i] также является указателем.Поэтому нет необходимости применять адресный оператор к names [i], чтобы search_names [i] указывал на ту же строку, что и names [i].Надеюсь, это прояснит для вас вещи.

1 голос
/ 21 августа 2010

Итак, вы пытаетесь скопировать имена массивов в search_names? Обратите внимание, что имена и search_names являются указателями на символы. IE, names [i] - это указатель.

Выражение

search_names[i] = names[i]

Назначает значение search_names [i] для имен [i]. Это просто помещает содержимое в стек времени выполнения с адресом и именами [i] в ​​ячейку с адресами и именами поиска [i]. В этом случае это просто копирование указателя. Это НЕ будет копировать символы. Он ТОЛЬКО скопирует содержимое из имен ячеек [i] - указатель на первый символ последовательности символов.

Причина, по которой

search_names[i] = names[i]++; 

эквивалентно

search_names[i] = names[i]

в контексте search_names объясняется тем, что оператор приращения влияет на значение имен [i]. Он имеет более низкий приоритет после оператора присваивания. Таким образом, выражение будет увеличивать имена [i] после присваивания. Так как names [i] является указателем, приращение выполняет некоторую арифметику указателя, что означает, что он будет указывать на адрес (names [i] + sizeof (char)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...