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

Прежде чем я начну, позвольте мне отметить это, чтобы продолжить этот пост, вам нужно знать, что такое C. Так как C — это язык программирования высокого уровня для низкоуровневого взаимодействия с аппаратным обеспечением, как скомпилировать C с использованием gcc или mingw или что-то еще, что вы предпочитаете, и базовый синтаксис C (циклы, переменные, условные выражения и т. д.). Также я буду ссылаться на книгу Денниса Ритчи здесь и там, так что держите ее под рукой.

Указатели. Указатель — это переменная, содержащая адрес переменной. Указатели широко используются в C, отчасти потому, что иногда они являются единственным способом выражения вычислений, а отчасти потому, что они обычно приводят к более компактному и эффективному коду, который можно получить другими способами. ~ Ссылка на язык программирования C Денниса Ритчи

Ладно, что мы тогда понимаем. Первым делом напишем программу и уточним нашу позицию с переменной.

Итак, у нас есть переменная int размера? и хранится по адресу? .

Примечание: я не уверен, почему повторные запуски программы возвращают один и тот же адрес «a». Я предполагаю, что я запускаю bash не изначально, т.е. весь процесс будет работать в рамках этого процесса, и Windows не позволит дочернему процессу получить доступ к резервам памяти вне своего контекста. Короче Windows будет решать, где и что выделять, не я и даже не мой компилятор, скажем.

Теперь сосредоточьтесь на печати. Я печатаю местоположение или адрес, где в памяти находится переменная «a», или, по крайней мере, то, что ОС хотела бы, чтобы мы считали доступной памятью. Значение его не имеет значения. Это адрес. &a дает вам адрес любого объекта в памяти, который существует в данный момент времени его выполнения. Зачем подчеркивать это, потому что вам могут понадобиться эти пункты позже для отладки вашего кода. 😃

И что делают указатели, точно так же, как int содержит целые числа или числа с плавающей точкой содержат числа с плавающей запятой, указатели содержат числа, которые, по сути, являются ссылкой на ячейку памяти, где что-то хранится. Теперь, если вам интересно, дает ли это вам доступ практически к любому месту в вашей оперативной памяти ?? Ответ абсолютно нет. Насколько вы знаете, ваша программа может находиться в каком-то файле подкачки на мгновение, потому что Windows решила, что это так, а более важные вещи находятся в ОЗУ (например, AC odyssey 😛)

PS: для простоты указатели можно рассматривать как шестнадцатеричные числа, но это не так, это просто ссылки на адреса виртуальной памяти. Но как программисту вам не нужно беспокоиться, если только вы не пишете ядра, в этом случае вы не будете читать эту статью. https://softwareengineering.stackexchange.com/questions/286226/what-is-the-type-of-data-that-pointers-hold-in-the-c-language

Разыменование указателя

Это должно прояснить ситуацию. Используйте приведенный выше образ непрерывной памяти и попытайтесь вписать его в вашу голову того, что только что произошло. А ведь это легко, просто попробуйте! Ну хотя бы до сих пор?

Помните две важные операции: & оператор дает адрес переменных в памяти (соответствующих объектов в памяти) и * т.е. оператор разыменования дает содержимое адресат.е. содержимое, удерживаемое адресом на который указывает указатель. Просто переменная оповещения жаргона, содержащая значение, и указатель, содержащий значение, означает, что одна и та же вещь использует ту же ассоциацию, что и у вас для переменных, аналогично указатель, указывающий на какой-то адрес, означает то же самое, то есть он может указывать только на то, что он содержит.

Вы можете изменить код, чтобы увидеть, имеет ли значение указатель символа или указатель с плавающей запятой. Да, просто для ознакомления код использует тип данных int и указатель int для ссылки на местоположение памяти переменных объектов int. Замените int на char или любой другой тип данных, который вам нравится, результаты могут измениться или не измениться в зависимости от того, какой компилятор вы используете.

Арифметика указателя

Теперь, если адреса памяти были похожи на номер дома. Тогда всякая логическая операция, которую можно проделать с домом нет. также допустимо с указателем, т.е. вы можете добавить смещение в память, добавить постоянное значение или добавить переменную. Умножение двух указателей невозможно в их собственном формате указателя. Приведите содержимое указателя к некоторому собственному арифметическому типу данных, а затем умножьте. Потому что умножение адресов имеет большой смысл !!!!! 😆

приоритет оператора: https://www.tutorialspoint.com/cprogramming/c_operators_precedence.htm

Теперь это может произойти впервые, когда вы используете арифметику указателя при разыменовании. Здесь происходит приоритет оператора. Поскольку ++ имеет более высокий приоритет при чтении слева направо, он выполняется первым, а оператор *p++ превращается в *(p++) . Ничего не могу поделать. Просто языковая структурная проблема или особенность 😬!

Таким образом, практическое правило всегда заключает в круглые скобки любую операцию разыменования. Просто чтобы не случилось таких неожиданных вещей. Попробуйте посмотреть, что дает ++*p. Это должно работать как обычно.

Приложения

Функция обмена (обмен на месте)

Наиболее распространенный пример, который используется для демонстрации использования указателя. Итак, функция C работает с передачей по значению. Это значение, которое вы передаете аргументам функции при вызове функции, на самом деле только копирует содержимое передаваемых значений.

function(a , b)
{ 
  printf("%p %p", a , b); 
  return a+b;
}
int a = 10;
int b = 20;
printf("%p %p" , a , b);
function(a , b)

Просто попробуйте приведенный выше код, и вы поймете, что я имею в виду. ‹a,b› в функции не совпадают с переданными им ‹a,b›. Только их значения совпадают. Теперь предположим, что вам нужна функция, которая меняет местами исходные ‹a,b›. Вы не можете просто поменять местами функцию, мы знаем, что это просто скопированное содержимое, поэтому исходные объекты памяти ‹a,b› остаются невредимыми. Что мы можем сделать, так это передать указатель, то есть местоположение оригинала ‹a,b›, а затем выполнить над ними некоторую операцию. Таким образом, мы гарантируем, что не будет создан новый объект или копия переменной, и все операции будут выполняться «вместо» памяти оригинала ‹a,b›.

Я надеюсь, что все это имело смысл до сих пор. Вы также должны обратиться к книге. В книге есть еще один очень хороший пример работающей программы для чтения целых чисел. Если вы считаете, что это не удобно для читателей или новичков. Я не могу не согласиться. Но попробуйте уложить в голове, что происходит, и вы поймете приложение.

Так что это было все на этот раз. В следующей статье об указателях мы увидим, что такое массивы. Что такое указатель на указатель. Указатели функций и многомерные указатели против многомерного массива.