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

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

 

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

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

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

Каждая переменная в памяти имеет свой адрес — номер первой ячейки, где она расположена, а также свое значение. Указатель — это тоже переменная, которая размещается в памяти. Она тоже имеет адрес, а ее значение является адресом некоторой другой переменной. Переменная, объявленная как указатель, занимает 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:
Расположение в памяти переменной и указателя

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


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

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

  • В связке Geany и GCC на Windows %x необходимо заменить %p. И будет такой вопрос, как эту связку научить выводить русские шрифты, может кто использует.

  • Алексей
    Здраствуйте, есть задание записать по указанному адресу указанное значение (без использования переменных). Это возможно? Как?

    • Елена Вставская
      Представить адрес как указатель и записать значение по этому адресу:
      1
      *((int*)0x8000)=1;
      В 4 байта, начиная с адреса 0x8000, будет записано значение 1.

  • Здравствуйте, Елена. Можете объяснить как работает 5-я строчка, что-то напоминает преобразование типов, но я не понимаю:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    uint32_t convert(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
    {
      uint32_t result=0;          //сюда мы будем собирать результат
      uint8_t *i;                 //указатель
      i = (uint8_t *) (&amp;result);   //считываем адрес куда помещаем //Как оно работает???
      *i = pgm_read_byte(digits+a); //преобразовали в соотв. код сегментов и кинули первую цифру
      i++;     //шагнули на один байт(потому что тип uint8_t) в памяти
      *i = pgm_read_byte(digits+b); //преобразовали в соотв. код сегментов и кинули вторую цифру
      i++;   //шагнули на один байт(потому что тип uint8_t) в памяти
      *i = pgm_read_byte(digits+c); //преобразовали в соотв. код сегментов и кинули третью цифру
      i++;   //шагнули на один байт(потому что тип uint8_t) в памяти
      *i = pgm_read_byte(digits+d); //преобразовали в соотв. код сегментов и кинули четвертую цифру
      return result; //вернули результат
    }
    Спасибо.

    • Елена Вставская
      i указывает на ту ячейку, в которой находится result, только при разыменовании будет получать 1-байтные данные

      • Спасибо за ответ! Извините, что с комментами "пристреливался". Но все равно мало понятен смысл сего выражения, механизм то я примерно понимаю. Может его как-то можно записать в формате для дурачков? Как пример data >>= 1, на самом деле будет data = (data >> 1).

        • Елена Вставская
          Смысл - сложить в одно 32-битное число result четыре байта, содержащие коды цифр последовательно.

  • Здравствуйте.У меня дилетантский вопрос по указателям.Есть несколько статических массивов типа: unsigned char[x].Мне нужно объединить эти массивы в один большой массив.Причем эти массивы будут повторятся несколько раз в большом массиве.Можно это сделать с помощью указателей? или это возможно только перезаписью элементов массива через циклы.В других языках есть специальные функции добавить массив в массив,сложить элементы массивов и др...Есть ли такие функции в библиотеках С или самому писать?


      • Сергей Владимирович
        Елена, Добрый день! У меня есть программа на Си для работы с оборудованием, точнее с электронным табло на которое в режиме on-line выводятся данные. Программа рабочая, но периодически появляются ошибки. Подозреваю, что не очень корректно происходит работа с указателями. Можно получить Вашу консультацию по этому вопросу? Заранее спасибо за ответ.

        • Елена Вставская
          Все материалы размещены на сайте. Индивидуальные консультации готова обсуждать в индивидуальном порядке, а не через комментарии. Пишите в форму обратной связи или в ВК

  • Владимир
    FILE* fp; fopen_s(&fp, "C:\\Documents and Settings\\User\\Рабочий стол\\Source\\test_enc.txt", "wb"); fwrite(decoded, 1, strlen((char*)decoded), fp); fclose(fp); Компилятор указывает на ошибку во второй строке. Пишет, что функция fopen_s не определена. Библиотек (#include <stdio.h>) подключенf. В чем может быть причина ?

  • Владимир
    Добрый вечер. Задача такая. Есть две функции, одна кодирует строку из восьми символов, другая раскодирует то что было закодировано (используется алгоритм шифрования/дешифрования TEA). Шифрация и дешифрация проходят успешно. Проблема такая: функция дешифрации uint32_t* decrypt(uint32_t* v, uint32_t* k)возвращает указатель на массив uint32_t* decoded = decrypt(plain, key); В возвращаемом массиве 2 тридцатидвухбитных числа, которые и есть результат раскодирования. Как имея эти два числа получить символьную строку чтобы было видно, что строки на входе и на выходе совпадают. Строку надо поместить в массив из восьми элементов типа char.

  • Владимир
    Добрый день.
    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    // Функция кодирования текста

    uint32_t* encrypt(uint32_t* v, uint32_t* k)
    {                                          
        uint32_t v0 = v[0];
        uint32_t v1 = v[1];
        uint32_t sum = 0;

        /* a key schedule constant */
        uint32_t delta = 0x9e3779b9;

        /* cache key */
        uint32_t k0 = k[0];
        uint32_t k1 = k[1];
        uint32_t k2 = k[2];
        uint32_t k3 = k[3];
        uint32_t i;

        /* basic cycle start */
        for (i = 0; i < 32; i++)
        {
            sum += delta;
            v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
            v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        }
        /* end cycle */

        v[0] = v0;
        v[1] = v1;

        j = 0;

        return v; // Возвращаем указатель на нулевой элемент массива зашифрованного числа

    }

    // Функция декодирования текста

    uint32_t* decrypt(uint32_t* v, uint32_t* k)
    {

        /* set up */
        uint32_t v0 = v[0];
        uint32_t v1 = v[1];
        uint32_t sum = 0xC6EF3720;
        uint32_t i;

        /* a key schedule constant */
        uint32_t delta = 0x9e3779b9;

        /* cache key */
        uint32_t k0 = k[0];
        uint32_t k1 = k[1];
        uint32_t k2 = k[2];
        uint32_t k3 = k[3];        

        /* basic cycle start */
        for (i = 0; i < 32; i++)
        {                              
            v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
            v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
            sum -= delta;
        }
        /* end cycle */

        v[0] = v0;
        v[1] = v1;

        return v;

    }

    uint32_t* plain;
    char shelf1[8]; // В массив записан текст из 8-символов
    char shelf2[8];

    plain = (uint32_t*)shelf1; // Загружаем текст в plain
    uint32_t* encoded = encrypt(plain, key); // Шифруем текст

    uint32_t* decoded = decrypt(plain, key); // Расшифровываем текст
    Правильно я понимаю, что функция decrypt возвращает указатель на первый элемент массива v ? Как расшифрованный текст поместить в символьный массив shelf2 ?

    • Елена Вставская
      Да, указатель на массив - это указатель на его начальный элемент. Текст можно переместить в массив посимвольным копированием. Либо передать указатель на результирующий массив в функцию и там его заполнить.


      • Владимир
        Массив v имеет тип uint32_t. В двух элементах этого массива содержаться два числа. Как эти два числа преобразовать в текстовый массив ?

        • Елена Вставская
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          #include <stdio.h>
          int main()
          {
            int a[2] = { 0x31323334, 0x35363738 };
            printf("%d %d\n", a[0], a[1]);
            char* s = (char*)a;
            for (int i = 0; i < 8; i++)
              printf("%d ", s[i]);
            getchar();
            return 0;
          }

          • Владимир
            Елена, покажите, пожалуйста, результат выполнения программы.


          • Владимир
            Елена, вы в какой среде программы на C пишите ?


          • Владимир
            1
            2
            3
            char key_buffer[KEY_SIZE];
            uint32_t* key;
            key = (uint32_t*)key_buffer;
            В последней строке текста, как я понимаю, в указатель key загружается адрес первого элемента массива key_buffer. Елена, а зачем перед key_buffer прописано (uint32_t*) ? Что это означает ?

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

          • Владимир
            uint32_t* key; key = (uint32_t*)key_buffer; Указатель key объявлен, зачем его переопределять ?

          • Елена Вставская
            key_buffer имеет другой тип, поэтому его нужно явно привести к нужному типу

          • Владимир
            1
            2
            3
            char key_buffer[KEY_SIZE];
            uint32_t* key;
            key = (uint32_t*)key_buffer;
            Вы написали: key_buffer имеет другой тип, поэтому его нужно явно привести к нужному типу. Это делается для того чтобы (1 х 8)= 8 байт key_buffer занести в (4 х 2) = 8 байт key ? При этом key_buffer[0] попадет в младший байт key[0] ? И еще два делитантских вопроса: 1)сможет ли компилятор C# без ошибок откомпилировать код, написанный на C или на C++; 2) чем язык C# принципиально отличается от C++.

          • Елена Вставская
            1 - Да 2 - Нет, C# не откомпилирует этот код без ошибок. Там вообще явная работа с указателями пользователю не предоставляется.

          • Владимир
            Добрый вечер, Елена. Есть функция, вот ее фрагмент:
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            uint32_t* decrypt(uint32_t* v, uint32_t* k)
            {

                /* set up */
                uint32_t v0 = v[0];
                uint32_t v1 = v[1];

                ............

               v[0] = v0;
               v[1] = v1;

                return v;
            }
            Вызов функции такой:
            1
            uint32_t* decoded = decrypt(plain, key);
            Функция возвращает указатель decoded на массив uint32_t v[2]. Как используя этот указатель перенести массив v[2] в символьный массив char mas2[8].

          • Елена Вставская
            Если mas2 - это статический массив, а не указатель, то только копированием значений

          • Владимир
            1
            2
            fopen_s(&ptrFile, "D/Source/test_enc.txt", "wb");
            fwrite(decoded, 1, BLOCK_SIZE, ptrFile);
            В продолжение к предыдущему. Елена,корректны ли эти две строки ? Здесь, как я понимаю, в первой строке открывается файл на запись. Во второй строке при помощи указателя decoded, указывающего на массив v[2] из функции в файл что пишется ? Прокоментируйте, пожалуйста подробно, обе строки.

          • Елена Вставская
            Корректность строк проще проверить компилятором) Насколько я помню,
            1
            ptrFile=fopen("D:\\Source\\test_enc.txt", "wb");

      • Владимир
        Добрый вечер. Елена, помогите разобраться в странной ситуации. У меня на ПК установлены две ОС, W'XP и W'7. В среде DevC++ , она из-под W'7 работает, написана программа на C++. Суть этой программы такова: на жестком диске есть папка, в которой хранятся два файла, исходный и результирующий (test.txt и test_enc.txt соответственно). Программа читает исходный файл с диска, кодирует его по алгоритму шифрования TEA, далее раскодирует закодированный текст и записывает текст в результирующий файл. В итоге тексты в исходном и результирующем файлах должны совпасть. Все нормально компилируется. Запускаю программу на исполнение. Смотрю файл test_enc.txt, а там вместо исходного текста какая-то ерунда записалась. Далее перезапускаю ПК, перехожу в W'XP, открываю файл test_enc.txt и вижу там исходный текст. Почему в W'7 текст в файл test_enc.txt отображается не верно, а в W'XP верно. Для просмотра содержимого файла в обеих ОС пользуюсь программой Блокнот. Что это такое и как это можно исправить ?

  • Владимир
    Добрый день. В программе есть такой фрагмент кода
    1
    2
    uint32_t p[] = {0xDEADBEEF, 0xCAFEBABE};
    uint32_t* plain = p;
    plain - это указатель. Прежде чем использовать указатель надо определить его значение, т.е. занести туда адрес переменной. В программе значение p не задано. В связи с этим возникает вопрос: В операторе uint32_t* plain = p; p куда пишется ?

    • Елена Вставская
      p - это адрес начала массива. Можно напечатать
      1
      printf("%p",p);
      чтобы узнать его значение

  • Есть такая часть кода SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4))); Я понимаю что этот метод позволяет выполнить прыжок в другую область памяти, начиная с addr + 4. Всё прекрасно работает. Но мне не понятны эти действия с указателями, помогите, пожалуйста, разобраться с этим механизмом

    • Елена Вставская
      Значение, которое хранится по адресу addr+4, используется как указатель на uint32_t (адрес), и идёт обращение к значению по этому адресу, которое, в свою очередь, является адресом функции, не принимающей аргументов и возвращающей указатель, который присваивается SysMemBootJump

  • Владимир
    Запутался совсем. Надо организовать многоуровневое меню. У каждого пункта в корневом (0) уровне имеется свой индивидуальный набор подпунктов. Надо как-то универсально по индексам работать с 1м и последующими уровнями и чтобы не расходовать память впустую. у меня есть такие описатели: char * menu1_1[4] = { "пункт1", "пункт2", "абвгд", "иклмн" }; char * menu1_2[2] = { "пункт10", "пункт14" }; char * menu1_3[6] = { "п/п2", "пунктХ", "абвгд", "п/п3", "п/п4", "п/п5"}; char * menu1_4[26] = { "п/п4", ... , "п/п30"}; // я тут сократил многоточием char *** mnu1; // вот здесь вот проблема //например если в корневом меню выбран 3й пункт, тогда mnu1 = &menu1_3; // и здесь проблема mnu1_length = 6; чтобы потом получить индексированный доступ к нужным строкам наподобие i=2; t14.txt = **mnu1[i]; // должен дать указатель на строку "пунктХ". Всем моим функциям надо кормить только указатели на строки для работы. можно конечно использовать многомерные массивы (как у меня сейчас), но получается ощутимый расход памяти впустую (большая система меню). Нигде не нашел никакого подобного решения на си.

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

      • Владимир
        Ну да. И каждый раз эту базу полностью перелопачивать чтобы обеспечить скроллинг, либо делать вспомогательные массивы (текущее меню и порядок входа). Плюс расход на каждую строку текста по 2 id, ну и еще 2 id, показывающие предыдущий и последующий пункт меню. В общем как я понял указателями в си такую задачу не решить (указатель на массив указателей на строки). Только структура+массивы+индексы...

  • Я тоже мучался с указателями 3 месяца. Понял только сегодня! Итак, что сбивало с толку, например здесь я _неправильно думал_ что
    1
    2
    int a=100; 
    int *p=&a; // я думал, что адрес переменной а присваивается "*p" (звездочке p).
    То есть я думал, что *p - "звездочкаП" это некое неделимое имя, что НЕВЕРНО! Все сразу понимается четко и верно, как только поставить пробел между звездочкой и p!!!
    1
    2
    int a=100; 
    int * p= &amp;a; 
    Здесь сразу понимаешь, что int * это определитель типа данных (который, кстати можно записать и как int*), а вот после того как тип данных определен, уже идет присваивание к имени p адреса переменной a, что естественно, так как имени p присвоен тип указатель (который может хранить только адрес), прохождение к этому адресу ведет к значению int, лежащему по этому адресу.
    Я это долго не мог понять, пока не наткнулся на двойные типы даных, такие как long long и мне сразу стала понятна конструкция int *p=&a; просто еще раз говорю, для лучшего понимания ставьте мысленно пробел между *_и_p, это сразу будет наглядно и понятно! int *p=&a; превращается в int * p=&a;
    Надеюсь это поможет многим в понимании как понять запись указателей!

    • Не надо никаких "мысленных" пробелов! Я всегда пишу так: int* p = &a; и сразу видно что тип p - это именно "указатель на int".

      • А как ты будешь 2 переменные указывать? int* ptr, ptr1; //ptr1 - тип будет int, а не int *


  • Я как понял int a[]; и int *arr; это одно и тоже? Почему тогда такая запись возможна: int *arr[]; а такая нет int **arr; это же должно соответствовать записи int arr[][]; Хотелось бы, чтобы вы прокомментировали все эти 5 типов записей, и как они взаимосвязаны

    • Елена Вставская
      Следует различать статические массивы, которые описываются с помощью квадратных скобок, и динамические массивы, для описания которых используются указатели. Для статического массива память выделяется в момент объявления. Для динамического массива - с помощью специальных функций динамического выделения памяти (malloc(), new).
      1
      2
      3
      4
      5
      int arr[10]; // одномерный статический массив из 10 элементов типа int
      int *arr; // указатель, которому может быть присвоен адрес начала динамического массива
      int *arr[10]; // массив из 10 указателей, каждому из которых должен быть присвоен адрес своей выделенной области памяти
      int **arr; // указатель на указатель, то есть массив указателей (см.строчку выше), размер которого тоже будет определен позднее
      int arr[10][10]; // двумерный статический массив

  • Помогите разобраться, у меня не компилировался свой код, потом попробовал ваш код из темы копи-пастнуть, ошибка аналогичная. Подскажите пожалуйста, что ему не нравится? 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() нужен, чтобы задержать консоль (чтобы программа сразу не закрылась, и пользователь мог посмотреть результат)


  • Давайте разберем тогда этот код :
    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;
    }
    здесь использубтся указатели , помогите понять для чего они нужны здесь ?

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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

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