Чтение строки с помощью scanf - PullRequest
130 голосов
/ 23 марта 2011

Я немного смущен чем-то. У меня сложилось впечатление, что правильный способ чтения C-строки с scanf() шел по линии

(не говоря уже о возможном переполнении буфера, это всего лишь простой пример)

char string[256];
scanf( "%s" , string );

Однако, похоже, работает и следующее:

scanf( "%s" , &string );

Это просто мой компилятор (gcc), чистая удача или что-то еще?

Ответы [ 2 ]

125 голосов
/ 23 марта 2011

Массив "разлагается" на указатель на свой первый элемент, поэтому scanf("%s", string) эквивалентно scanf("%s", &string[0]). С другой стороны, scanf("%s", &string) передает указатель на char[256], но указывает на то же место.

Затем scanf при обработке хвоста списка аргументов попытается извлечь char *. Это правильно, когда вы ввели string или &string[0], но когда вы ввели &string, вы зависите от того, что не гарантирует языковой стандарт, а именно от того, что указатели &string &string[0] - указатели на объекты разных типов и размеров, начинающиеся в одном и том же месте, - представлены одинаково.

Я не думаю, что когда-либо сталкивался с системой, в которой это не работает, и на практике вы, вероятно, в безопасности. Тем не менее, это неправильно, и это может дать сбой на некоторых платформах. (Гипотетический пример: реализация «отладки», включающая информацию о типе с каждым указателем. Я думаю, реализация C на символике «Машины Лиспа» сделала нечто подобное.)

0 голосов
/ 21 марта 2017

Я думаю, что это ниже, верно, и это может помочь.Не стесняйтесь исправлять это, если вы обнаружите какие-либо ошибки.Я новичок в C.

char str[]  
  1. массив значений типа char, со своим собственным адресом в памяти
  2. массив значений типа char, со своим собственным адресом вПамять столько последовательных адресов, сколько элементов в массиве
  3. , включая нулевой символ завершения '\0' &str, &str[0] и str, все три представляют одно и то же место в памяти, которое является адресомпервый элемент массива str

    char * strPtr = & str [0];// объявление и инициализация

альтернативно, вы можете разделить это на две части:

char *strPtr; strPtr = &str[0];
strPtr - указатель на char strPtr точек на массиве str strPtr - переменная со своим собственным адресом в памяти strPtr - это переменная, в которой хранится значение адреса &str[0] strPtr собственный адрес в памяти отличается от адреса памяти, который он хранит (адрес массива в памяти aka & str [0]) &strPtr представляет адрес самого strPtr

Я думаю, что вы можете объявить указатель на указатель следующим образом:

char **vPtr = &strPtr;  

объявляет и инициализируетс адресом указателя strPtr

В качестве альтернативы вы можете разделить на две части:

char **vPtr;
*vPtr = &strPtr
*vPtr указывает на указатель strPtr *vPtr - это переменная с собственным адресом в памяти *vPtr - это переменная, в которой хранится значение адреса & strPtr последний комментарий: вы не можете сделать str++, str адрес это const, но вы можете сделать strPtr++
...