Указатели в си примеры: присваивание, разыменование и перемещение по массивам / Хабр

Основанные указатели (C++) | Microsoft Learn

Twitter LinkedIn Facebook Адрес электронной почты

  • Статья
  • Чтение занимает 2 мин

Ключевое __based слово позволяет объявлять указатели на основе указателей (указатели, которые являются смещениями от существующих указателей). Ключевое __based слово зависит от Корпорации Майкрософт.

Синтаксис

type __based( base ) declarator

Указатели, основанные на адресах указателей, являются единственной формой ключевого слова, допустимой __based в 32-разрядных или 64-разрядных компиляциях. В 32-разрядном компиляторе Microsoft C/C++ относительный указатель имеет 32-разрядное смещение от 32-разрядной базы указателя. То же ограничение действует и для 64-разрядных сред, где относительный указатель имеет 64-разрядное смещение от 64-разрядной базы указателя.

Указатели на основе указателей, в частности, используются для постоянных идентификаторов, которые содержат указатели. Связанный список, состоящий из указателей на основе указателей, можно сохранить на диск, а затем перезагрузить в другое место в памяти. При этом все указатели останутся действительными. Пример:

// based_pointers1.cpp
// compile with: /c
void *vpBuffer;
struct llist_t {
   void __based( vpBuffer ) *vpData;
   struct llist_t __based( vpBuffer ) *llNext;
};

Указателю vpBuffer назначается адрес в памяти, который выделяется на более позднем этапе программы. Связанный список перемещается относительно значения vpBuffer.

Примечание

Сохранение идентификаторов, содержащих указатели, также можно выполнить с помощью сопоставленных в памяти файлов.

Когда выполняется разыменовывание относительных указателей, база должна быть либо явно указана, либо неявно известна из объявления.

Для совместимости с предыдущими версиями _based

является синонимом__based, если не указан параметр компилятора /Za (отключить расширения языка).

Пример

В следующем примере демонстрируется изменение относительного указателя путем изменения его базы.

// based_pointers2.cpp
// compile with: /EHsc
#include <iostream>
int a1[] = { 1,2,3 };
int a2[] = { 10,11,12 };
int *pBased;
typedef int __based(pBased) * pBasedPtr;
using namespace std;
int main() {
   pBased = &a1[0];
   pBasedPtr pb = 0;
   cout << *pb << endl;
   cout << *(pb+1) << endl;
   pBased = &a2[0];
   cout << *pb << endl;
   cout << *(pb+1) << endl;
}
1
2
10
11

См.

также раздел

Ключевые слова
alloc_text

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

Мы знаем, что указатели — это адреса переменных в памяти и, как правило, числовые. Вот почему мы можем производить некоторые арифметические вычисления и с указателями. Эти вычисления можно производить так же, как мы делаем с числовыми значениями в математике или программировании. Поэтому мы обсудим некоторые арифметические операции над указателями в нашем учебном руководстве с использованием C ++. Мы использовали систему Ubuntu 20.04, убедившись, что в ней настроен компилятор G ++. Начнем с реализации арифметики указателей в оболочке системного терминала Ubuntu 20.04 с помощью сочетания клавиш Ctrl + Alt + T, используемого на его рабочем столе.

Содержание

  1. Пример 1
  2. Пример 2
  3. Пример 3
  4. Заключение

Пример 1

Начните первый пример кода C ++, чтобы использовать арифметические операторы «+» для указателей при создании файла. Вы можете создать файл разными способами, но самый простой — использовать «сенсорную» инструкцию. Таким образом, мы попробовали ключевое слово touch вместе с заголовком файла, который нужно сформировать на консоли, и нажали Enter. Файл создается в домашней папке Ubuntu 20.04.

Теперь, чтобы открыть этот только что созданный файл, вы можете использовать любой из встроенных редакторов, поставляемых с Ubuntu 20.04, то есть vim, текстовый редактор или редактор GNU nano. Мы предлагаем вам использовать редактор GNU Nano, поскольку мы использовали его в оболочке, как показано на изображении ниже.

Этот файл «pointer.cc» пока не заблокирован в редакторе. Мы включили заголовочный файл потока ввода-вывода в первую строку, а стандартное пространство имен было использовано во второй строке. Мы инициализировали целочисленную переменную «v» значением 8. В следующей подряд строке мы инициализировали указатель целочисленного типа «p». Этот указатель является адресом переменной «v», поскольку он связан с переменной «v» с помощью знака «&». Это означает, что мы можем изменить адрес изменяемого объекта в любое время. Стандартные операторы cout использовались один за другим. Первый отображает исходный адрес переменной «v», сохраненный как указатель «p».

В следующей строке оператор cout увеличивает адрес указателя на 1 и отображает его. Следующие две строки использовали указатель и увеличивали его значение на 2 и 3. Увеличенные значения были отображены с помощью оператора cout. Код заканчивается здесь. Давайте сначала сохраним код перед выполнением. Для этого используйте Ctrl + S. Вы должны выйти из редактора GNU Nano, чтобы вернуться к терминалу. Для этого воспользуйтесь сочетанием клавиш «Ctrl + X». Это был простейший код C ++ для увеличения указателя с помощью оператора +.

Вернувшись к оболочке, мы должны сделать наш код безошибочным. Для этого используется компилятор C ++. Ключевое слово компилятора «g ++» было использовано вместе с именем файла, который должен быть скомпилирован, например, «pointer.cc». Компиляция прошла успешно, поскольку вы видите, что она ничего не возвращает. Давайте выполним наш безошибочный код с помощью стандартной команды «./a.out». У нас есть 4 разных адреса для переменной «v».

Первый — это исходный адрес «p» переменной «v». Второй увеличивается на 1, третий увеличивается на значение 2, а последний увеличивается на 3. Каждый раз, когда мы выполняем приращение, последние два символа адреса имеют тенденцию изменяться, как показано ниже.

Пример 2

Приведем еще один пример использования оператора декремента для указателя. Итак, мы использовали все тот же старый файл «pointer.cc». Пространство имен и заголовок ввода-вывода используются так же, как и раньше. Другая постоянная целочисленная переменная «s» инициализируется постоянным значением 5. В методе main () мы использовали массив целочисленного типа с именем «v» размера «s» с 5 элементами в нем. Объявлен целочисленный указатель «p». Указатель был привязан к целочисленному массиву «v» с помощью знака «&».

Размер будет начинаться с адреса s-1. Инициализирован цикл for, который начинается с размера 5 и работает в порядке убывания, каждый раз уменьшаясь на 1. Каждый раз, когда цикл for работает, он отображает адрес памяти номера индекса, повторяемого циклом, и значение в конкретном индексе, а также с использованием стандартного оператора cout. «P» показывает адрес индекса, а * P представляет значение этого конкретного индекса. На каждой итерации указатель уменьшался на 1. На этом заканчивается цикл и основная функция.

Сначала скомпилируйте код с помощью компилятора g ++ языка C ++. Он работает успешно, без ошибок. Выполнение осуществляется командой «./a.out». Мы получили результат, как показано ниже. Как видите, у нас есть каждый адрес памяти для определенного индекса, то есть 5,4,3,2,1 в порядке убывания индексов. С другой стороны, мы также получаем значения в каждом конкретном индексе каждый раз, когда цикл повторяется в порядке убывания до последнего значения.

Пример 3

У нас будет новый экземпляр указателей. В этом примере мы будем сравнивать адреса указателей, а также значения, которые они содержат. Таким образом, документ pointer.cc теперь запускается в редакторе GNU Nano. Функция main () была инициализирована после стандартного пространства имен и заголовка потока «io» в файле кода. Он содержит две переменные строкового типа s1 и s2 с совершенно разными строковыми значениями, то есть «Aqsa» и «Yasin».

После этого мы инициализировали две переменные-указатели строкового типа p1 и p2, ограниченные обеими переменными s1 и s2, с помощью символа «&» после знака «=». Это означает, что указатель p1 — это адрес переменной s1, а p2 — адрес переменной s2.

Первое стандартное предложение cout используется для отображения результата сравнения обоих указателей, то есть адресов обеих строковых переменных. Если адреса совпадают, в оболочке будет отображаться 1 как истина, в противном случае 0 как ложь. Второе стандартное предложение cout используется для отображения результата сравнения значений, хранящихся в конкретном адресе указателя. Если значения совпадают, возвращается 1, в противном случае — 0. Программа сравнения на этом заканчивается.

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

Немного изменим код. Откройте тот же файл и обновите строковые значения. Одни и те же строковые переменные s1 и s2 были инициализированы одинаковыми значениями, то есть Aqsa. Остальной код используется без изменений, как и раньше. Сохраните свой код, чтобы получить обновленный результат.

Мы получили 0 как результат сравнения адресов указателей, поскольку обе переменные содержат разные адреса памяти, и 1 как результат сравнения значений, то есть одинаковые значения обеих строк.

Заключение

Мы обсудили арифметические операции, выполняемые над указателями. Также мы использовали арифметические операторы увеличения и уменьшения для указателей. Мы также обсудили бонусные примеры, чтобы проиллюстрировать работу оператора сравнения с двумя разными указателями.

Сборка

— В чем практическая разница между регистрами SI и DI?

спросил

Изменено 9 лет, 1 месяц назад

Просмотрено 61к раз

Часть коллектива Intel

Не понимаю в чем разница.

  • сборка
  • x86
  • регистры процессора

0

Когда вы используете такие инструкции, как movsb, si считается регистром нашего источника s , а di — регистром назначения d . Но они оба являются обычными регистрами x86.

Моя сборка немного ржавая, но один индекс источника, другой индекс назначения. Инструкция типа movsb скопирует байт из ячейки памяти, на которую указывает SI , и переместит его в ячейку памяти, на которую указывает DI , а затем увеличит оба значения, поэтому, если вы хотите скопировать байт, хранящийся в SI+1

до DI+1 требуется только дополнительная инструкция movsb.

SI означает исходный индекс. Исходный индекс используется в качестве указателя на текущий символ, считываемый в строковой инструкции (LODS, MOVS или CMPS). Исходный индекс также доступен в качестве смещения для добавления Bx или Bp при косвенной адресации.
пример:

 MOV [Bx + SI], Ax
 

Эта инструкция копирует содержимое Ax в ячейку памяти, адрес которой представляет собой сумму Bx и SI.

DI означает индекс назначения, используемый в качестве указателя на текущий записываемый или сравниваемый символ в строковой инструкции.

Он также доступен как смещение, как и SI.

, как сказано выше, di обозначает целевой индекс, а si обозначает исходный индекс, когда мы хотим переместить данные из памяти, мы используем si, например, mov ax,[si]. и когда мы хотим переместить данные в память, мы используем di. например, mov [di],ax

оба являются 16-битными регистрами и не могут быть разделены на 8-битные

1

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью Google

Зарегистрироваться через Facebook

Зарегистрируйтесь, используя электронную почту и пароль

Опубликовать как гость

Электронная почта

Требуется, но не отображается

Опубликовать как гость

Электронная почта

Требуется, но не отображается

Рабочий пример для указателей на структуры в C

спросил

Изменено 4 года, 7 месяцев назад

Просмотрено 748 раз

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

В этом примере кода, который я нашел здесь, я все еще получаю ужасную ошибку:

предупреждение: назначение из несовместимого типа указателя

 #include 
структура Книга
{
    имя персонажа[10];
    внутренняя цена;
}
основной ()
{
    структура Книга а; //Одна структурная переменная
    структура Книга* ptr; //Указатель типа структуры
    указатель = &а;
    структура Книга b[10]; // Массив структурных переменных
    структура Книга* p; //Указатель типа структуры
    р = &б;
    вернуть 0;
}
 

У кого-нибудь есть рабочий пример , на котором я мог бы поучиться?

  • c
  • указатели
  • структура

6

Изменение:

 p = &b;
 

В:

 р = б;
 

Это потому, что b [уже] является массивом. Итак, b сам по себе относится ко всему массиву, а результат указывает на первый элемент (т. е. &b[0] ). То, что у вас было, генерирует Book ** вместо Book * [1].

Таким образом, это также сработает:

 р = &b[0];
 

ОБНОВЛЕНИЕ:

[1] Плохо. Это фактически генерирует структуру Book (*)[10] , которая является указателем на массив фиксированного размера (например, 10) структур Book , который [немного] отличается от простого указателя Book . Это добавляет длину массива как часть типа, поэтому сопоставление указателя/типа является более строгим/сложным.

A struct Book (*)[10] не соответствует [по типу] struct Book * и не будет соответствовать другому указателю фиксированного размера массива длины (например, struct Book (*)[20] ), даже если базовый тип ( struct Book ) тот же.

Однако после определения разыменование/индексация указателя будет аналогичным.

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *