Указатель в языке Си

Язык Си / Указатель в языке Си

 

Указатель — переменная, содержащая адрес объекта. Указатель не несет информации о содержимом объекта, а содержит сведения о том, где размещен объект.

Указатели широко используются в программировании на языке Си.
Указатели часто используются при работе с массивами.

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

Каждая переменная в памяти имеет свой адрес — номер первой ячейки, где она расположена, а также свое значение. Указатель — это тоже переменная, которая размещается в памяти. Она тоже имеет адрес, а ее значение является адресом некоторой другой переменной. Переменная, объявленная как указатель, занимает 4 байта в оперативной памяти (в случае 32-битной версии компилятора).

Указатель, как и любая переменная, должен быть объявлен.
Общая форма объявления указателя

 
тип *ИмяОбъекта;


Тип указателя— это тип переменной, адрес которой он содержит.

Для работы с указателями в Си определены две операции:

  • операция * (звездочка) — позволяет получить значение объекта по его адресу — определяет значение переменной, которое содержится по адресу, содержащемуся в указателе;
  • операция & (амперсанд) — позволяет определить адрес переменной.

Например,

 
 
 
сhar c;   // переменная
char *p; // указатель
p = &c;  // p = адрес c


Указатель
Для указанного примера обращение к одним и тем же значениям переменной и адреса представлено в таблице

Переменная Указатель
Адрес &c p
Значение c *p

Пример на Си

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
int main()
{
  int a, *b;
  system("chcp 1251");
  system("cls");
  a = 134;
  b = &a;
  // %x = вывод числа в шестнадцатеричной форме
  printf("\n Значение переменной a равно %d = %x шестн.", a,a);
  printf("\n Адрес переменной a равен %x шестн.", &a);
  printf("\n Данные по адресу указателя b равны %d = %x шестн.", *b,*b);
  printf("\n Значение указателя b равно %x шестн.", b);
  printf("\n Адрес расположения указателя b равен %x шестн.", &b);
  getchar();
  return 0;
}

Результат выполнения программы:
Использование указателя

Расположение в памяти переменной a и указателя b:
Расположение в памяти переменной и указателя

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


Назад: Язык Си

Комментариев к записи: 27


  • школа прок
    Даже с картинками! Вы молодцы что старались так доходчиво объяснить



    • Елена Вставская
      Потому что шестнадцатеричное число 0x86 равно десятичному 134.

  • Спасибо, я даже и не ожидал, что так быстро ответите) Я читаю K&R, как нам в школе рекомендовали, но, видимо, пропускаю какие-то моменты, книга очень концентрированная.

  • заметил,  что удобно запоминать: Адрес с Амперсандом, Значение - со Звездочкой

  • Вечный студент
    Чудесный у вас сайт, Елена! Изучал С по K&R, задачи у них долгоиграющие, отвлекают от изучения С. Пока решишь их задачи, забудешь, что изучал ). А у вас все здорово, просто оттяг какой-то! КР до конца не довел, некогда, пишу сейчас проги под winapi, иногда нужно быстро что-то вспомнить, особенно то, что и не знал или наискосок прочитал. Ваш сайт для таких быстрых справок - находка! Не сразу понял, почему значение b перевернуто на нижней картинке слева направо. Программа то выдает значение 93f7b8. А потом увидел выше, что адреса слева направо увеличиваются. Все нормально! А потом прочел еще про прямую адресацию и совсем хорошо стало. )   Спасибо вам за помощь людям!

  • "Каждая переменная в памяти имеет свой адрес — номер первой ячейки, где она расположена, а также свое значение." Создаётся впечатление, что переменная состоит из трёх частей: 1. номер первой ячейки 2. где она расположена 3. свое значение

  • Здравствуйте Елена, из прочитанного понял, что символ "звездочка" (*)применяется в Си в различных операциях: "объявление указателя", "присваивание значения через указатель", "умножение". На ваш взгляд в этом какой то смысл, может необходимость, или просто создатели Си так захотели и все тут. Спасибо за понятные для "начинающих" уроки.

    • Елена Вставская
      Это синтаксис языка, и нужно принять его как должное. Вы же не спрашиваете, какой смысл писать слово "парашют" с Ю в корне слова :)

      • Несомненно вы правы, что при изучении необходимо строго придерживаться синтаксиса языка, но в том то и дело, что изучая указатели я вижу, что строго определенного синтаксиса то и нет, эту звездочку (*)толкают куда кому вздумается при объявлении указателя, что сбивает с толку человека начавшего изучать Си:
        1
        2
        3
        int *p;
        int* p; 
        int * p;
        Какой же это синтаксис,это полная анархия:) Было бы неплохо услышать ваш комментарий по этому поводу, или ссылку. Спасибо.

        • Елена Вставская
          Пробел в данном случае роли не играет, но звёздочка обязательно должна стоять перед именем при объявлении указателя.

  • Такой вопрос : Зачем нужны указатели ? это как ссылка на объект в других высокоуровневых языках?

    • Елена Вставская
      Указатель - это переменная, значением которой является адрес. Часто указатели применяются, например, для обращения к динамически выделенной памяти. Ссылка - это не то же самое. Ссылка - это ещё одно имя объекта, а сама по себе ссылка объектом не является.

  • Давайте разберем тогда этот код :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #include <stdlib.h>
    #include <gtk/gtk.h>
    #include <sqlite3.h>

    void helloWorld (GtkWidget *wid, GtkWidget *win)
    {
        GtkWidget *dialog = NULL;

        dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
                                         GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, sqlite3_libversion());
        gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
        gtk_dialog_run (GTK_DIALOG (dialog));
        gtk_widget_destroy (dialog);
    }

    int main (int argc, char *argv[])
    {
        GtkWidget *button = NULL;
        GtkWidget *win = NULL;
        GtkWidget *vbox = NULL;

        /* Initialize GTK+ */
        g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, (GLogFunc) gtk_false, NULL);
        gtk_init (&argc, &argv);
        g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, g_log_default_handler, NULL);

        /* Create the main window */
        win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        gtk_container_set_border_width (GTK_CONTAINER (win), 8);
        gtk_window_set_default_size (GTK_WINDOW (win), 400, 200);
        gtk_window_set_title (GTK_WINDOW (win), "Hello World");
        gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
        gtk_widget_realize (win);
        g_signal_connect (win, "destroy", gtk_main_quit, NULL);

        /* Create a vertical box with buttons */
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
        gtk_container_add (GTK_CONTAINER (win), vbox);

        button = gtk_button_new_from_stock (GTK_STOCK_DIALOG_INFO);
        g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (helloWorld), (gpointer) win);
        gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);

        button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
        g_signal_connect (button, "clicked", gtk_main_quit, NULL);
        gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);

        /* Enter the main loop */
        gtk_widget_show_all (win);
        gtk_main ();
        return 0;
    }
    здесь использубтся указатели , помогите понять для чего они нужны здесь ?

    • Елена Вставская
      Они нужны для получения указателей (в частности, на создаваемое окно). А также для передачи параметров в функцию.

      • Значит мы создаем указатель на окно , кнопку и другие элементы управления , и когда надо передать их в функцию мы не передаем всю информацию о них а передаем адрес памяти где лежит информация ? Тогда функция должна быть объявлена изначально с аргументами тип которых - указатели Получается как в высокоуровневых языках передача аргументов по ссылке или по значению


  • Помогите разобраться, у меня не компилировался свой код, потом попробовал ваш код из темы копи-пастнуть, ошибка аналогичная. Подскажите пожалуйста, что ему не нравится? vladislav@My-Comp:~/Рабочий стол/CodeC$ gcc pointers.c -o pointers.exe pointers.c: In function ‘main’: pointers.c:12:62: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=] printf("\n Адрес переменной a равен %x шестн.", &a); ~^ ~~ %ls pointers.c:14:66: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=] printf("\n Значение указателя b равно %x шестн.", b); ~^ %ls pointers.c:15:85: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat=] ntf("\n Адрес расположения указателя b равен %x шестн.", &b); ~^ ~~

    • Елена Вставская
      Судя по всему, Ваш компилятор в шестнадцатеричном виде желает выводить только числа типа unsigned int. Чтобы не было ошибки, нужно явно привести все указатели к этому типу.
      1
      printf("\n Адрес переменной a равен %x шестн.", (unsigned int)(&a));

      • Антонина
        Добрый день! Подскажите, пожалуйста, какую роль играет в этой программе играет функция getchar ()?


          • Елена Вставская
            Это поддержка русского языка в окне консоли

        • Елена Вставская
          getchar() нужен, чтобы задержать консоль (чтобы программа сразу не закрылась, и пользователь мог посмотреть результат)

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

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