C: различия между символьным указателем и массивом [дубликат]

Указатель функции также указывает в память, единственная разница - то, что существует исполняемый код в той ячейке памяти вместо данных.

На многих платформах, при попытке выполнить данные (например, регулярная память) Вы разрушите или вызовете исключение. Это известно как Предотвращение Выполнения Данных - меры безопасности для предотвращения приложений, непреднамеренно выполняющих изворотливый код, который может быть помещен туда вредоносным программным обеспечением.

135
задан Peter Mortensen 25 March 2014 в 04:06
поделиться

10 ответов

Верно, но это небольшая разница. По сути, первое:

char amessage[] = "now is the time";

Определяет массив, члены которого находятся в пространстве стека текущей области, тогда как:

char *pmessage = "now is the time";

Определяет указатель, который живет в пространстве стека текущей области, но который ссылается на память в другом месте (в этом, "сейчас время "хранится в другом месте памяти, обычно в таблице строк).

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

Изменить: Как указали Марк, GMan и Павел, существует также разница, когда оператор адресации используется для любой из этих переменных. Например, & pmessage возвращает указатель типа char **, или указатель на указатель на символы, тогда как & amessage возвращает указатель типа char (*) [16] или указатель на массив из 16 символов (который, как и char **, должен быть разыменован дважды как точки litb вне).

96
ответ дан 23 November 2019 в 23:45
поделиться

Массив - это константный указатель. Вы не можете обновить его значение и указать в другом месте. Хотя для указки можно сделать.

-2
ответ дан 23 November 2019 в 23:45
поделиться

For this line: char amessage [] = «сейчас самое время»;

компилятор будет оценивать использование сообщения в качестве указателя на начало массива, содержащего символы «сейчас самое время». Компилятор выделяет память для «сейчас самое время» и инициализирует ее строкой «сейчас самое время». Вы знаете, где хранится это сообщение, потому что сообщение всегда ссылается на начало этого сообщения. Сообщение не может получить новое значение - это не переменная, это имя строки «сейчас самое время».

Эта строка: char * pmessage = "now is the time";

объявляет переменную pmessage, которая инициализирована (с заданным начальным значением) начального адреса строки "now is the time". В отличие от amessage, pmessage может быть присвоено новое значение. В этом случае, как и в предыдущем случае, компилятор также сохраняет «сейчас самое время» в другом месте памяти. Например, это приведет к тому, что pmessage будет указывать на букву «i», которая начинается со слова «это время». pmessage = pmessage + 4;

0
ответ дан 23 November 2019 в 23:45
поделиться

Первая форма ( сообщение ) определяет переменную (массив), которая содержит копию строки «сейчас время» .

Вторая форма ( pmessage ) определяет переменную (указатель), которая находится в другом месте, чем любая копия строки «сейчас время» .

Попробуйте вывод этой программы:

#include <inttypes.h>
#include <stdio.h>

int main (int argc, char *argv [])
{
     char  amessage [] = "now is the time";
     char *pmessage    = "now is the time";

     printf("&amessage   : %#016"PRIxPTR"\n", (uintptr_t)&amessage);
     printf("&amessage[0]: %#016"PRIxPTR"\n", (uintptr_t)&amessage[0]);
     printf("&pmessage   : %#016"PRIxPTR"\n", (uintptr_t)&pmessage);
     printf("&pmessage[0]: %#016"PRIxPTR"\n", (uintptr_t)&pmessage[0]);

     printf("&\"now is the time\": %#016"PRIxPTR"\n",
            (uintptr_t)&"now is the time");

     return 0;
}

Вы увидите, что хотя & amessage равно & amessage [0] , это неверно для & pmessage и & pсообщение [0] . Фактически, вы увидите, что строка, хранящаяся в amessage , живет в стеке, а строка, на которую указывает pmessage , живет где-то еще.

Последний printf показывает адрес строковый литерал. Если ваш компилятор выполняет «объединение строк», то будет только одна копия строки «сейчас самое время» - и вы увидите, что ее адрес не совпадает с адресом сообщения amessage . Это потому, что сообщение получает копию строки при инициализации.

В конце концов, суть в том, что сообщение сохраняет строку в своем собственная память (в этом примере в стеке), тогда как pmessage указывает на строку, которая хранится в другом месте.

4
ответ дан 23 November 2019 в 23:45
поделиться

Второй выделяет строку в некоторой секции ELF, доступной только для чтения. Попробуйте выполнить следующее:

#include <stdio.h>

int main(char argc, char** argv) {
    char amessage[] = "now is the time";
    char *pmessage = "now is the time";

    amessage[3] = 'S';
    printf("%s\n",amessage);

    pmessage[3] = 'S';
    printf("%s\n",pmessage);
}

, и вы получите ошибку сегментации при втором назначении (pmessage [3] = 'S').

3
ответ дан 23 November 2019 в 23:45
поделиться

Если массив определен так, что его размер доступен во время объявления, sizeof (p) / sizeof (type-of-array) вернет количество элементов в массиве.

5
ответ дан 23 November 2019 в 23:45
поделиться

Я не могу добавить что-то полезное к другим ответам, но замечу, что в Deep C Secrets Питер ван дер Линден подробно описывает этот пример. Если вы задаете такие вопросы, я думаю, вам понравится эта книга.


PS Вы можете присвоить новое значение pmessage . Вы не можете присвоить новое значение сообщению ; он неизменный .

6
ответ дан 23 November 2019 в 23:45
поделиться

Вместе с памятью для строки "now" "время" распределяется в двух разных местах, вы также должны помнить, что имя массива действует как значение указателя в отличие от переменной указателя , которой является pmessage. Основное отличие состоит в том, что переменная-указатель может быть изменена так, чтобы указывать где-то еще, а массив не может.

char arr[] = "now is the time";
char *pchar = "later is the time";

char arr2[] = "Another String";

pchar = arr2; //Ok, pchar now points at "Another String"

arr = arr2; //Compiler Error! The array name can be used as a pointer VALUE
            //not a pointer VARIABLE
4
ответ дан 23 November 2019 в 23:45
поделиться

Массив содержит элементы. На них указывает указатель.

Первый - это краткая форма выражения

char amessage[16];
amessage[0] = 'n';
amessage[1] = 'o';
...
amessage[15] = '\0';

, то есть это массив, содержащий все символы. Специальная инициализация инициализирует его за вас и автоматически определяет его размер. Элементы массива можно изменять - в нем можно перезаписывать символы.

Вторая форма - это указатель, который просто указывает на символы. Он хранит символы не напрямую. Поскольку массив является строковым литералом, вы не можете взять указатель и записать туда, куда он указывает

char *pmessage = "now is the time";
*pmessage = 'p'; /* undefined behavior! */

Этот код, вероятно, выйдет из строя на вашем ящике. Но он может делать что угодно, потому что его поведение не определено.

12
ответ дан 23 November 2019 в 23:45
поделиться

Вот гипотетическая карта памяти, показывающая результаты двух объявлений:

                0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
    0x00008000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00008008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
        ...
amessage:
    0x00500000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00500008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
pmessage:
    0x00500010:  0x00  0x00  0x80  0x00

Строковый литерал «сейчас - время» хранится как 16-элементный массив символов по адресу памяти 0x00008000 . Эта память может быть недоступна для записи; лучше предположить, что это не так. Никогда не следует пытаться изменить содержимое строкового литерала.

Объявление

char amessage[] = "now is the time";

выделяет массив из 16 элементов char по адресу памяти 0x00500000 и копирует в него содержимое строкового литерала. Эта память доступна для записи; вы можете изменить содержимое сообщения по своему усмотрению:

strcpy(amessage, "the time is now");

Объявление

char *pmessage = "now is the time";

выделяет единственный указатель на char по адресу памяти 0x00500010 и копирует адрес строкового литерала к нему.

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

strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " ");      /* OKAY */
strtok(pmessage, " ");      /* NOT OKAY */
scanf("%15s", amessage);      /* OKAY */
scanf("%15s", pmessage);      /* NOT OKAY */

и так далее. Если вы изменили pmessage так, чтобы он указывал на amessage:

pmessage = amessage;

, то его можно использовать везде, где можно использовать сообщение.

144
ответ дан 23 November 2019 в 23:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: