C Символьные указатели

Скажем, у нас есть массив указателей:

char *ptr[30];

Теперь это прекрасно работает и, похоже, ничего неожиданного! Я могу легко вводить имена.

 scanf("%s", ptr[1]); scanf("%s", ptr[2]); scanf("%s", ptr[3]); printf("%s\n", ptr[1]); printf("%s\n", ptr[2]); printf("%s\n", ptr[3]); 

Мой вопрос в том, может ли указатель использоваться таким образом, чтобы хранить конечное число имен, тогда почему используется malloc.? и в этом случае ptr [1] не указывает на символ на входе, а на новый вход. например, если ptr имеет mukul, ptr [1] должен указывать на «u», и если пространство не выделяется, когда указатель объявлен таким образом, каковы пределы.?

Указатель не может использоваться таким образом. Он может «работать» для вас иногда по чистой случайности, но использование указателя без выделения памяти для него приведет к неопределенному поведению – это означает, что ваша программа может вести себя беспорядочно и дать неожиданные результаты.

Помните, только потому, что ваша компиляция и запуск вашей программы не означает, что она правильная. На языке C существует целый class ошибок, известный как «неопределенное поведение», многие из которых компилятор с радостью позволит вам без жалобы. К ним относятся перезапись буфера, использование неинициализированной переменной или разыменование указателя, который не указывает на законно выделенный блок памяти. Программы, которые демонстрируют неопределенное поведение, могут даже казаться нормально работать иногда – но они, как правило, очень нестабильны и склонны к сбою.

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

Когда вы определяете указатель наподобие:

 char *ptr = 0; // NULL pointer: dereferencing it will crash puts(ptr); // crash 

Вы просто создаете ссылку на место в памяти:

 ptr = "string"; // dereferencing it will show the string puts(ptr); // displaying "string" 

Таким образом, наличие массива указателей просто создает список ссылок на другие переменные.

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

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

 Адрес позиции 0x00 0x01 0x02 0x03
 ---- ------ ---- ---- ---- ---- ----
 ptr 0xbbc81230 0x ??  0x ??  0x ??  0x ??
            0xbbc81234 0x ??  0x ??  0x ??  0x ??
            0xbbc81238 0x ??  0x ??  0x ??  0x ??
            ...
            0xbbc812a8 0x ??  0x ??  0x ??  0x ??           

где 0x?? представляет собой случайное значение байта. Для описанного вами поведения каждое из случайных значений просто указывает на записываемую память, и запись над тем, что там хранится, просто не имеет каких-либо непосредственных побочных эффектов.

Bad juju: похоже, что ваш код работает правильно, когда на самом деле он ведет себя очень плохо, и может привести к некоторым неприятным проблемам времени исполнения в другом месте вашей программы, что больно отлаживать.

Вам нужно будет явно установить каждый элемент массива ptr чтобы указать на допустимую ячейку памяти, прежде чем пытаться ее прописать.

Предположим, мы добавим следующий код:

 ptr[0] = malloc(strlen("foo") + 1); strcpy(ptr[0], "foo"); ptr[1] = malloc(strlen("bar") + 1); strcpy(ptr[1], "bar"); 

Мы динамически выделили дополнительную память для хранения нескольких строк и сохранили указатели на эти новые буферы до ptr[0] и ptr[1] .

Теперь наша картина будет выглядеть примерно так:

 Адрес позиции 0x00 0x01 0x02 0x03
 ---- ------ ---- ---- ---- ---- ----
            0x80ff0000 'f' 'o' 'o' 0x00
            ...
            0x80ffcdc0 'b' 'a' 'r' 0x00
            ...
 ptr 0xbbc81230 0x80 0xff 0x00 0x00
            0xbbc81234 0x80 0xff 0xcd 0xc0
            0xbbc81238 0x ??  0x ??  0x ??  0x ??
            ...
            0xbbc812a8 0x ??  0x ??  0x ??  0x ??           

ptr[0] теперь содержит адрес буфера размером 4 char , и мы копируем строку «foo» в этот буфер. Аналогично, ptr[1] содержит адрес другого 4-байтового буфера, который теперь содержит строку «bar».