Указатель в языке Си
Указатель на языке Си — это переменная, которая хранит адрес другой переменной. Он может иметь тип int, char, array, function или любой другой указатель. Размер указателя зависит от архитектуры. Однако в 32-битной архитектуре размер указателя составляет 2 байта.
Рассмотрим следующий пример, чтобы определить указатель, который хранит адрес целого числа.
int n = 10;
int* p = &n; // Переменная p типа указатель указывает на адрес переменной n типа integer.
Объявление указателя
Указатель на языке си может быть объявлен с помощью * (символ звездочки). Он также известен как косвенный указатель, используемый для разыменования указателя.
int *a;//указатель на int
char *c;//указатель на char
Пример использования указателей для печати адреса и значения приведен ниже.
Как вы можете видеть на приведенном выше рисунке, переменная указателя хранит адрес переменной числа, то есть fff4. Значение переменной number равно 50. Но адрес переменной указателя p-aaa3.
С помощью * (оператор косвенности) мы можем вывести значение переменной указателя p. Давайте рассмотрим пример указателя, как описано на приведенном выше рисунке.
#include
int main() <
int number=50;
int *p;
p=&number;//хранит адрес числовой переменной
printf(«Адрес переменной p равен %x \n»,p); // p содержит адрес числа, поэтому печать p дает адрес числа.
printf(«Значение переменной p равно %d \n»,*p); // Поскольку мы знаем, что * используется для разыменования указателя, поэтому, если мы напечатаем *p, мы получим значение, хранящееся по адресу, содержащемуся в p.
return 0;
>
Выход
Адрес числовой переменной fff4
Адрес переменной p-fff4
Значение переменной p равно 50
Указатель на массив
intarr[10];
int *p[10]=&arr; // Переменная p типа pointer указывает на адрес целочисленного массива arr.
Указатель на функцию
voidshow (int);
void(*p)(int) = &display; // Указатель p указывает на адрес функции
Указатель на структуру

Преимущества указателя
- Указатель сокращает код и повышает производительность, он используется для извлечения строк, деревьев и т. Д. и используется с массивами, структурами и функциями.
- Мы можем возвращать несколько значений из функции с помощью указателя.
- Это позволяет вам получить доступ к любой ячейке памяти в памяти компьютера.
Использование указателя
Существует множество применений указателей на языке си.
Динамическое выделение памяти
В языке си мы можем динамически выделять память с помощью функций malloc() и calloc (), где используется указатель.
Массивы, функции и структуры
Указатели на языке си широко используются в массивах, функциях и структурах. Это сокращает код и повышает производительность.
Адрес Оператора (&)
Адрес оператора ‘&’ возвращает адрес переменной. Но нам нужно использовать %u для отображения адреса переменной.
#include
int main() <
int number=50;
printf(«значение числа — %d, адрес числа — %u»,number,&number);
return 0;
>
Выход
значение числа равно 50, адрес числа-fff4
Нулевой Указатель
Указатель, которому не присвоено никакого значения, кроме NULL, называется нулевым указателем. Если у вас нет никакого адреса, который должен быть указан в указателе во время объявления, вы можете присвоить нулевое значение. Это обеспечит лучший подход.
В большинстве библиотек значение указателя равно 0 (нулю). Указательная программа для замены двух чисел без использования 3-й переменной.
Выход
Перед свопом: *p1=10 *p2=20
После свопа: *p1=20 *p2=10
Чтение сложных указателей
Есть несколько вещей, которые должны быть приняты во внимание при чтении сложных указателей в C. Давайте посмотрим на приоритет и ассоциативность операторов, которые используются в отношении указателей.
| Оператор | Приоритет | Ассоциативность |
| (), [] | 1 | Слева направо |
| *, идентификатор | 2 | Справа налево |
| Тип данных | 3 | — |
Здесь мы должны заметить, что:
- (): Этот оператор является скобочным оператором, используемым для объявления и определения функции.
- []: Этот оператор является оператором индекса массива
- * : Этот оператор является оператором указателя.
- Идентификатор: Это имя указателя. Приоритет всегда будет отдаваться этому.
- Тип данных: Тип данных-это тип переменной, на которую должен указывать указатель. Он также включает в себя модификатор типа signedint, long и т. д.).
Как читать указатель: int (*p)[10].
Чтобы прочитать указатель, мы должны увидеть, что () и [] имеют одинаковый приоритет. Поэтому здесь необходимо учитывать их ассоциативность. Ассоциативность находится слева направо, поэтому приоритет отдается ().
Внутри скобки () оператор указателя * и имя указателя (идентификатор) p имеют одинаковый приоритет. Поэтому их ассоциативность должна быть рассмотрена здесь справа налево, поэтому приоритет идет к p, а второй приоритет идет к *.
Назначьте 3-й приоритет [], так как тип данных имеет последний приоритет. Поэтому указатель будет выглядеть следующим образом.
Указатель будет считываться как p-указатель на массив целых чисел размера 10.
Как прочитать следующий указатель?
Этот указатель будет считываться как p-указатель на такую функцию, которая принимает первый параметр как указатель на одномерный массив целых чисел размера два, а второй параметр как указатель на функцию, параметр которой является пустым, а тип возвращаемого значения-целым.
Преимущества (использование) указателей в c:
- Указатели обеспечивают прямой доступ к памяти
- Указатели позволяют возвращать функции более одного значения
- Уменьшает объем памяти и сложность программы
- Сокращает время выполнения программы
- Предоставляет альтернативный способ доступа к элементам массива
- Указатели могут использоваться для передачи информации между вызывающей функцией и вызываемой функцией.
- Указатели позволяют нам выполнять динамическое выделение и освобождение памяти.
- Указатели помогают нам создавать сложные структуры данных, такие как связанный список, стек, очереди, деревья, графики и т. Д.
- Указатели позволяют нам изменять размер динамически выделяемого блока памяти.
- Адреса объектов могут быть извлечены с помощью указателей
Недостатки указателей в c:
- Неинициализированные указатели могут вызвать ошибку сегментации.
- Динамически выделяемый блок должен быть освобожден явно. В противном случае это приведет к утечке памяти.
- Указатели работают медленнее, чем обычные переменные.
- Если указатели обновляются с неверными значениями, это может привести к повреждению памяти.
В принципе, ошибки указателей трудно отлаживать. Ответственность программистов за эффективное и правильное использование указателей.
Передача указателя на функцию в C с примером
В этом примере мы передаем указатель на функцию. Когда мы передаем указатель в качестве аргумента вместо переменной, вместо значения передается адрес переменной. Таким образом, любое изменение, произведенное функцией с помощью указателя, постоянно производится по адресу передаваемой переменной. Этот метод известен как вызов по ссылке в C.
Попробуйте эту же программу без указателя, вы обнаружите, что сумма бонуса не будет отражаться в зарплате, это потому, что изменение, произведенное функцией, будет сделано с локальными переменными функции.
#include
voidsalaryhike(int *var, int b)
<
*var = *var+b;
>
int main()
<
intsolary=0, bonus=0;
printf(«Введите текущую зарплату сотрудника:»);
scanf(«%d», &solary);
printf(«Введите бонус:»);
scanf(«%d», &bonus);
salaryhike(&solary, bonus);
printf(«Конечная зарплата: %d», solary);
return 0;
>
Выход:
Введите текущую зарплату сотрудника:10000
Введите бонус:2000
Итоговая зарплата: 12000
Замена двух чисел с помощью указателей
Это один из самых популярных примеров, который показывает, как менять номера с помощью вызова по ссылке. Попробуйте эту программу без указателей, вы увидите, что числа не меняются местами. Причина та же, что мы видели выше в первом примере.
#include
voidswapnum(int *num1, int *num2)
<
inttempnum;tempnum = *num1;
*num1 = *num2;
*num2 = tempnum;
>
int main( )
<
int v1 = 11, v2 = 77 ;
printf(«Перед заменой:»);
printf(«\nЗначение v1: %d», v1);
printf(«\nЗначение v2: %d», v2);/*вызов функции swap*/
swapnum(&v1, &v2 );printf(«\nAfter swapping:»);
printf(«\Значение v1: %d», v1);
printf(«\nЗначение v2: %d», v2);
>
Выход:
Перед обменом:
Значение v1 равно: 11
Значение v2 равно: 77После обмена:
Значение v1 равно: 77
Значение v2 равно: 11
Заключение
В этом уроке мы узнали как пользоваться указателями языка C, пишите свои вопросы в комментариях
Как передать указатель в функцию c
При рассмотрении передачи параметров в функцию указывалось, что параметры передаются в функцию по значению. То есть функция не изменяет значения передаваемых аргументов. Однако, используя в качестве параметров указатели, мы можем получить доступ к значению аргумента и изменить его.
Например, пусть у нас будет простейшая функция, которая увеличивает число на единицу:
Здесь переменная n передается в качестве аргумента для параметра x. Передача происходит по значению, поэтому любое изменение параметра x в функции increment никак не скажется на значении переменной n. Что мы можем увидеть, запустим программу:
Теперь изменим функцию increment, использовав в качестве параметра указатель:
Теперь в функции increment разыменовываем указатель, получаем его значение и увеличиваем его на единицу.
Это изменяет значение, которое находится по адресу, хранимому в указателе x.
Поскольку теперь функция в качестве параметра принимает указатель, то при ее вызове необходимо передать адрес переменной: increment(&n); .
В итоге изменение параметра x также повлияет на переменную n:
Еще один показательный пример применения указателей в параметрах — функция обмена значений:
Функция swap() в качестве параметров принимает два указателя. Посредством переменной temp происходит обмен значениями.
При вызове функции swap в нее передаются адреса переменных x и y, и в итоге их значения будут изменены.
Константые параметры
Если необходимо запретить изменять значение параметра-указателя внутри функции, то можно определить такой параметра как константный:
Фактически такой константный параметр будет работать как указатель на константу — мы не сможем изменить его значение внутри функции.
Массивы в параметрах
Если функция принимает в качестве параметра массив, то фактически в эту функцию передается только адрес начала массива. То есть как и в случае с указателями нам доступен адрес, по которому мы можем менять значения. В отличие от параметров примитивных типов, которые передаются по значению.
Например, определим функцию для увеличения элементов массива в два раза:
Функция twice в качестве параметров принимает массив и число его элементов и в цикле увеличивает их в два раза.
В функции main передаем массив в функцию twice и затем выводим его на консоль. В результате мы увидим, что массив nums был изменен:
Так как передача массива в функцию фактически представляет передачу адреса первого элемента, то массивы в параметрах мы можем заменить указателями:
В итоге в данном случае не будет большой разницы, какой тип имеет параметр — массив или указатель.
Передача в функцию указателя или ссылки [дубликат]
Программы выведут одно и то же? Ведь и так, и так мы обращаемся к существующему элементу, а не создаем новый.
В принципе, технически разница между указателем и ссылкой лишь в том, что саму ссылку нельзя изменить (а указатель можно). [Вот тут бóльший список отличий.] Кроме этого, разница ещё синтаксическая: с ссылкой вы обращаетесь как будто это переменная, а с указателем нужно его правильно получать/разыменовывать:
Других технических отличий нет, и результат будет одинаковый.
Но разница на самом деле не в синтаксисе, а в смысле, в семантике.
Указатель может означать всё, что угодно. Он в C и C++ означает строку, ассив, адрес переменной, передачу переменной по ссылке и ещё кучу всяких вещей. А смысл ссылки ровно один — это как бы альтернативное имя (alias) существующей переменной.
Поэтому для случаев наподобие того, который вы описали, в C++ уместно использовать ссылку, а не указатель. Хотя, как вы сами видите, с указателем тоже прекрасно работает.
И ещё: в чистом C ссылок нет, так что у вас нет другого варианта кроме указателей.
![]()
Ответы на ваш вопрос даны выше, разницы в поведении никакой, но хотел бы уточнить несколько нюансов.
1. Пока у вас простые типы разницы никакой (кроме описаной выше в других ответах, например про NULL значение переменной в случае указателя). Но как только дело дойдет до классов появится разница. В случае передачи в функцию указателя на класс то, в зависимости от реализации и решаемых задач, будет иметь место разыменовывание указателя. Сложность этой процедуры будет зависеть от размера класса. Это справделиво в случе разыменовывания всего класса и не касается доступа к отдельным его членам. Например: int c = b->d; //дешево , а A b = *A; //дороже
2. вы можете перегрузить оператор & , а * нет.
3. Указатели не могут принимать временные значения, в то время как const & могут. Например: void f(const &A);. f(A()); //возможно
4. В целом работа с ссылками проще, поэтому ведут к меньшему числу ошибок
Золотое правило с++ программиста: используй ссылки где можешь, а указатели где должен.
Если вы исправите опечатки и включите заголовок
То вывод будет идентичен.
Когда используются указатели, то вы можете передать null-указатель. Например,
И функция может быть вызвана как
Когда же используются ссылки, то ссылка должна указывать на существующий объект.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.3.11.43304
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Как передать указатель в функцию c
Передача через указатель
С точки зрения удобства программирования, передавать значения, которые могут изменяться внутри функции лучше всего через ссылку (а не через указатель). Чтобы в этом разобраться, ниже описан возможный, но не самый лучший способ передачи параметров — по указателю.
Если передавать параметры через указатель (так называемый С-стиль), код функции выглядит так:
mul5(&var); // Здесь символ & обозначает операцию взятия адреса переменной
Такой синтаксис неудобен. Внутри тела функции, перед переменной, которая является указателем, приходится ставить звездочку * для работы со значением, на который указывает указатель. Кроме того, при вызове функции приходится ставить амперсанд & перед именем переменной для того, чтобы передать адрес переменной (который будет принят в функцию как указатель).
Передача через ссылку
Если передавать параметры через ссылку , код функции выглядит так:
А вызов выглядит так:
Видно, что нет никаких разыменовываний в теле функции функции. Так же при таком вызове не требуется передача адреса переменной.
Однако, следует помнить , что такая передача по ссылке возможна только для единичных типов C/C++ . И не работает для передачи массивов!
Поэтому, к примеру, если функция принимает:
- одномерный массив block из элементов char , элементы которого надо изменить внутри функции (обозначим это как сложный/составной тип)
- целочислительную переменную shift , которую тоже надо изменить внутри функции (это простой базовый тип)
то реализация функции будет выглядеть так:
void clear(unsigned char *block, int &shift)
А вызов функции будет выглядеть так:
unsigned char* anyBlock="Long string";
for(int i=0; i<len; ++i)
clear(anyBlock, anyShift); // Вызов функции
То есть, в вызове нет никаких спецсимволов указателей/адресов ни для первого ни для второго параметра. Для первого параметра нет спецсимвола взятия адреса (хоть и идет работа с указателем) из-за того, что имя массива имеет тип указателя. Для второго параметра нет спецсимвола взятия адреса из-за того, что передача идет по ссылке.
При таком вызове будут изменяться как ячейки массива anyBlock , так и переменная anyShift .