2012-03-27 3 views
4

Скажем у нас есть массив указателей: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]); 

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

+7

Также необходимо отметить, что первым элементом в массиве является ptr [0]. – SirDarius

+0

Попробуйте сделать что-то между 'scanf' и 'printf'. Вы должны увидеть какое-то неопределенное поведение. – stanwise

+0

да ptr [0] определенно есть! Спасибо за ваш ответ! –

ответ

13

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

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

+0

Спасибо за ответ! –

+2

Также сообщите, что объявление char * ptr [30] указывает, что существует 30 указателей на символы, то есть он может указывать на 30 разных символов, потому что это массив указателей или он может указывать на 30 различных массивов символов (в этом случае имена) ? –

+0

Я имею в виду, что он должен указывать на 30 разных символов, но здесь он используется для указания 30 разных имен, это правильно.? –

4

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

+0

Спасибо большое, сэр! –

3

При определении указатель типа:

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

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

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

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

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

+0

поэтому указатель говорит char * c; может указывать на символ или он может указывать на массив символов ..? что более правильно. если он указывает только на одного символа, а затем выполняет C++ и что-то снова запоминает, он должен перезаписываться! –

+0

Указатель может указывать на любой размер данных, не обязательно одного и того же типа указателя. Независимо от того, является ли цель массивом, зависит от вас. Переменные - это места памяти. Указатели - это ссылки на память. – Gil

+0

Правильно, но указатель ++ всегда должен указывать на следующую ячейку памяти. И если массив был сохранен в предыдущем местоположении, это местоположение должно быть обработано? –

3

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

 
Item  Address  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: it выглядит как ваш код работает правильно, когда на самом деле он ведет себя очень плохо, и может привести к некоторым неприятным проблемам времени выполнения в другом месте вашей программы, что является болью для отладки.

Вам нужно будет явно установить каждый элемент массива 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].

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

 
Item  Address  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».

Смежные вопросы