|
Программирование >> Перегруженные имена функций и идентификаторы
будет известен под именем р и может указывать на любой символ (или непрерывный массив символов). Важно понимать, что сс1ка типа х[3] порождает разный код в зависимости от того, массив х или указатель. В случае выражения р[3] компилятор генерирует код, чтобы начать с позиции p , считывает значение указателя, прибавляет к указателю 3 и, наконец, читает символ, на который указывает указатель. Что понимается под эквивалентностью указателей и массивов в Си? Большая часть путаницы вокруг указателей в Си происходит от непонимания этого утверждения. Эквивалентность указателей и массивов не позволяет говорить не только об идентичности, но и о взаимозаменяемости. Эквивалентность относится к следующему ключевому определению: значение типа массив Т, которое появляется в выражении, превращается (за исключением трех случаев) в указатель на первый элемент массива; тип результирующего указателя - указатель на Т. (Исключение составляют случаи, когда массив оказывается операндом sizeof, оператора & или инициализатором символьной строки для массива литер.) Вследствие этого определения нет заметной разницы в поведении оператора индексирования [], если его применять к массивам и указателям. Согласно правилу, приведенному выше, в выражении типа a[i] сс1лка на массив а превращается в указатель и дальнейшая индексация происходит так, как будто существует выражение с указателем p[i] (хотя доступ к памяти будет различным). В любом случае выражение x[i], где х - массив или указатель) равно по определению *((x)+(i)). Почему объявления указателей и массивов взаимозаменяемы в в качестве формальных параметров? Так как массивы немедленно превращаются в указатели, массив на самом деле не передается в функцию. По общему правилу, любое похожее на массив объявление параметра: f(a) char a[]; рассматривается компилятором как указатель, так что если был передан массив, функция получит: char *a; Это превращение происходит только для формальных параметров функций, больше нигде. Если это превращение раздражает вас, избегайте его; многие пришли к выводу, что порождаемая этим путаница перевешивает небольшое преимущество от того, что объявления смотрятся как вызов функции и/или напоминают о том, как параметр будет использоваться внутри функции. Как массив может быть значением типа lvalue, если нельзя присвоить ему значение? Стандарт ANSI C определяет модифицируемое lvalue , но массив к этому не относится. Почему sizeof неправильно определяет размер массива, который передан функции в качестве параметра? Оператор sizeof сообщает размер указателя, который на самом деле получает функция. Кто-то объяснил мне, что массивы это на самом деле только постоянные указатели Это слишком большое упрощение. Имя массива - это константа, следовательно, ему нельзя присвоить значение, но массив - это не указатель. C практической точки зрения в чем разница между массивами и указателями? Массивы автоматически резервируют память, но не могут изменить расположение в памяти и размер. Указатель должен быть задан так, чтобы явно указывать на выбранный участок памяти (возможно с помощью malloc), но он может быть по нашему желанию переопределен (т.е. будет указывать на другие объекты) и, кроме того, указатель имеет много других применений, кроме службы в качестве базового адреса блоков памяти. В рамках так называемой эквивалентности массивов и указателей, массивы и указатели часто оказываются взаимозаменяемыми. Особенно это касается блока памяти, выделенного функцией malloc, указатель на который часто используется как настоящий массив. Я наткнулся на шуточный код, содержащий выражение 5[ abcdef ]. Почему такие выражения возможны в Си? Да, индекс и имя массива можно переставлять в Си. Этот забавный факт следует из определения индексации через указатель, а именно, a[e] идентично *((a)+(e)), для любого выражения е и основного выражения а, до тех пор пока одно из них будет указателем, а другое целочисленным выражением. Это неожиданная коммутативность часто со странной гордостью упоминается в С-текстах, но за пределами Соревнований по Непонятному Программированию (Obfuscated C Contest) Мой компилятор ругается, когда я передаю двумерный массив функции, ожидающей указатель на указатель Правило, по которому массивы превращаются в указатели не может применяться рекурсивно. Массив массивов (т.е. двумерный массив в Си) превращается в указатель на массив, а не в указатель на указатель. Указатели на массивы могут вводить в заблуждение и применять их нужно с осторожностью. (Путаница еще более усугубляется тем, что существуют некорректные компиляторы, включая некоторые версии pcc и полученные на основе pcc программы lint, которые неверно воспринимают присваивание многоуровневым указателям многомерных массивов.) Если вы передаете двумерный массив функции: int array[NROWS][NCOLUMNS]; f(array); описание функции должно соответствовать f(int a[][NCOLUMNS]) {...} f(int (*ap)[NCOLUMNS]) {...} /* ap - указатель на массив В случае, когда используется первое описание, компилятор неявно осуществляет обычное преобразование массива массивов в указатель на массив ; во втором случае указатель на массив задается явно. Так как вызываемая функция не выделяет место для массива, нет необходимости знать его размер, так что количество строк NROWS может быть опущено. Форма массива по-прежнему важна, так что размер столбца NCOLUMNS
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |