По краткому определению, указатель – это переменная, содержащая адрес другой переменной [7.1]. Так как указатель содержит адрес переменной (объекта), это дает возможность "косвенного" доступа к этой переменной (объекту) через указатель.
Для понимания работы и назначения указателей рассмотрим упрощенную схему организации памяти компьютера. Память представляет собой массив последовательно пронумерованных или адресованных ячеек, с которыми можно работать по отдельности или связанными кусками. Известно, что различным типам данных отводится определенное количество байтов памяти. Поэтому указатель – это группа ячеек, в которых может храниться адрес. Например, если переменная ch имеет тип char, а ptr (от латинского pointer – указатель) есть указатель на переменную ch, то взятие адреса переменной ch осуществляется с помощью унарного (одноместного) оператора , т.е.
ptr = ch;
Приведенная инструкция означает, что переменной ptr присваивается адрес ячейки ch. Принято считать, что ptr указывает на ch. Оператор применяется только к объектам, расположенным в памяти: к переменным, элементам массива. Операндом оператора не может быть ни выражение, ни константа, ни регистровая переменная [7.1]. называется еще оператором адресации [7.2].
Имена указателям даются в соответствии с правилами, принятыми в языке программирования С для обычных переменных.
Другая унарная операция * называется операцией ссылки по указателю ( indirection ), или разыменования ( dereferencing ). Если применить ее к указателю, то получим объект, на который он указывает. Рассмотрим пример. Пусть х и у – целые переменные, а *ptr – указатель на целую переменную. Поставим задачу присвоения переменной у значения переменной х с помощью указателя. Фрагмент С -кода будет следующий:
int x = 1, y = 2; int *ptr; // объявили указатель на целую переменную ptr = x; // взяли адрес переменной х = 1 y = *ptr; // переменная у стала равной 1 *ptr = 0; // переменная х стала равной 0
В приведенных объявлениях новым является объявление указателя:
int *ptr;
Следует помнить, что любой указатель может указывать только объекты одного конкретного типа данных, заданного при объявлении [7.1].
* есть оператор косвенного доступа. Примененный к указателю он выдает объект, на который данный указатель указывает.
Одноместные (унарные) операции * и имеют более высокий приоритет для своих операндов, чем арифметические операции.
Для указателей одного типа можно, например, выполнять присваивание без разыменования. Это вытекает из того, что указатели сами по себе являются переменными. Пусть определен еще один указатель типа int, например, ptr2.
Тогда возможно произвести присвоение:
ptr2 = ptr;
После присвоения указатель ptr2 будет указывать на ту же переменную, что и указатель ptr.
В языке С допустимы следующие (основные) операции над указателями: присваивание; получение значения того объекта, на который ссылается указатель (синонимы:
С помощью унарных операций "++" и "––" числовые (арифметические) значения переменных типа указатель меняются по-разному в зависимости от типа данных, с которыми связаны эти переменные [7.3]. Если указатель связан с типом char, то при выполнении операций "++" и "––" его числовое значение изменяется на 1 (единицу). Если указатель связан с типом int, то операции "++" и "––" изменяют числовые значения указателей на 2. Указатель, связанный с типами float или long, унарными операциями "++" и "––" изменяется на 4. Таким образом, при изменении указателя на единицу указатель "переходит к началу" следующего (или пр
едыдущего) поля той длины, которая определяется типом.
Следует особо остановиться на указателях и квалификаторе (модификаторе) const. Как известно, квалификатор const превращает переменную в константу, значение которой не должно меняться. Например, нет смысла изменять число $$\pi$$. Значение константы должно быть инициализировано в месте ее определения. В связи с этим различают указатели на константы и константные указатели [7.6]. Приведем следующий пример:
long value = 9999L; const long *pvalue = value;
Последняя строчка приведенного кода определяет собой указатель на константу. Попытка указателю pvalue присвоить иное числовое значение будет восприниматься компилятором как ошибка [7.6]. Но само значение переменной value изменять допустимо. При этом указатель держит адрес переменной, значение которой изменилось. В тоже время саму переменную также можно объявить с помощью квалификатора const. В этом случае нельзя изменять ни переменную, ни значение указателя (т. е. присвоить иное числовое значение указателю). Указатели на константы часто используются как формальные параметры функций (о функциях будет сказано позднее).
Константный указатель может адресовать как константу, так и переменную. В случае, когда определен константный указатель, то через него нельзя уже брать адрес другой переменной. Приведем следующий пример определения константного указателя:
int count = 43; int *const pcount = count;
Вторая строчка приведенного кода определяет и инициализирует константный указатель pcount, который "привязан" к адресу переменной count. Если определить новую переменную того же типа, то взять адрес новой переменной с помощью константного указателя pcount будет нельзя, компилятор сделает сообщение об ошибке и работа программы будет невозможной. В тоже время возможно изменить значение константного указателя через другое числовое значение. Но это повлечет за собой изменение переменной, на которую указатель ссылается. Например,
int count = 43; int *const pcount = count; *pcount = 345;
В соответствии с приведенным кодом переменная count будет иметь значение 345 [7.6].
Соответственно, если константный указатель ссылается на константный объект (например, на константную переменную), то в этом случае ни значение объекта, на который ссылается такой указатель, ни значение самого указателя (когда будет сделана попытка присвоить иное числовое значение указателю) не может быть изменено в программе. Например,
const int card = 21; const int *const pcard = card
Указанные особенности для указателей с квалификатором const присущи и для переменных (объектов) других типов.
Указатели, значения которых изменять нельзя используются, например, при заполнении константных таблиц.
Пример 1. Напишите программу определения адресов целых чисел от 0 до 9 и строчных букв латинского алфавита.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int i,
j = 0;
char c = 'a',
*ptr2;
ptr2 = c;
printf("\n\t Figures, symbols and their addresses:\n");
for (i = 0; i < 10; ++i)
printf("\n\t %3d) %2d --> %5p", i + 1, i, i);
printf("\n");
for ( ; *ptr2 <= 'z'; (*ptr2)++)
printf("\n\t %3d) %2c --> %5p", ++j, *ptr2, ptr2);
printf("\n\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.1.
(рис 7.1) Адреса цифр и строчных буквВ программе использован спецификатор формата %5p для определения
Задание 1
for примените операторы while.int и применить этот указатель по аналогии с указателем *ptr2.Пример 2. Напишите программу однозначного задания типа разностей указателей, и определения адресов заданных указателей.
Для решения данного примера подключим заголовок stddef.h для определения типа разности указателей с помощью зарезервированного имени типа ptrdiff_t.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
#include <stddef.h>
int main (void)
{
int x, y;
int *px, *py;
ptrdiff_t z;
// инициализация указателей
px = x;
py = y;
// разница двух указателей
z = px - py;
printf("\n The difference of two pointers to %p and %p is: %d", px, py, (int) z);
printf("\n\n The addresses are: px = %p, py = %p\n", px, py);
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.2.
(рис 7.2) Адреса указателей типа int и их разность
Задание 2
х и у. Проанализируйте результат выполнения программы.char, long int, long long int, unsigned int, float, double, long double.printf().Пример 3. Напишите программу арифметических операций с указателями.
При выполнении примера следует иметь в виду, что операции "" и "*" имеют более высокий приоритет, чем обычные арифметические операции. Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
int x = 2, y = 7, a, b, *ptr, *ptr2;
ptr = a;
ptr2 = b;
*ptr = x - y;
*ptr2 = y - x - *ptr + 100;
printf("\n\t Arithmetic operations with pointers:\n");
printf("\t a = %d, b = %d\n", a, b);
printf("\n Press any key: ");
_getch();
return 0; }
Результат выполнения программы показан на рис 7.3.
(рис 7.3) Результат арифметических операций с указателямиСледует обратить внимание на то, что переменные a и b сначала не были определены, а в результате стали иметь некоторые значения.
Задание 3
double и float.a и b, измените значения указателей на значения Х и 10*Х, где Х – номер компьютера, за которым выполняется лабораторная работа. Выполните указанные арифметические действия и выведите значения переменных a и b.printf().Пример 4. Напишите программу двухуровневой адресации для объектов целого типа.
Случай, когда указатель ссылается на указатель, который ссылается на число, называется многоуровневой адресацией [7.4]. В случае двухуровневой адресации первый указатель содержит адрес второго указателя, который содержит адрес объекта с нужным значением. Объявление указателя на указатель делается с помощью двух звездочек перед именем переменной. Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
int x, y = 8;
int *ptr, **ptr2;
x = 7;
ptr = x;
ptr2 = ptr;
**ptr2 = *ptr + 10;
printf("\n\t The value of x = %d. 1-st pointer is: %d. 2-nd pointer is: %d\n", x, *ptr, **ptr2);
ptr = y;
ptr2 = ptr;
**ptr2 = 88;
printf("\n\t The value of y = %d\n", y);
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.4.
(рис 7.4) Результат двухуровневой адресацииЗадание 4
Пример 5. Напишите программу по определению и инициализации переменных разных типов и одного указателя типа void *. Последовательно присваивая указателю
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void){
int x = 99;
double y = 6.78;
char symbol = '#';
void *ptr;
ptr = x;
printf("\n\t The value of variable through a pointer: %d\n", *(int *) ptr);
ptr = y;
printf("\n\t The value of variable through a pointer: %lf\n", *(double *) ptr);
ptr = symbol;
printf("\n\t The value of variable through a pointer: %c\n", *(char *) ptr);
printf("\n Press any key: ");
_getch();
return 0;}
Результат выполнения программы показан на рис 7.5.
(рис 7.5) Результат настройки указателя типа void
Особенностью использования указателя типа void является то, что при
Задание 5
float, unsigned, long и обеспечьте ввод их значений с клавиатуры. Выведите адреса и значения переменных с помощью разыменования указателя.void. Выведите значения двух указателей с помощью их разыменования.Пример 6. Напишите программу по реализации условия: определить и инициализировать переменную типа double. Определите указатели типа char *, int *, double *, void *, инициализируйте их адресом переменной. Выведите на экран пользователя значения указателей, их размеры и длины участков памяти, которые связаны с выражениями, разыменовывающими указатели [7.5].
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
double d = 6.78;
char *cp;
int *ip;
double *dp;
void *vp;
// Адресация с приведением типов
cp = (char *)d;
ip = (int *)d;
dp = (double *)d;
vp = d;
printf("\n\t Address:\n\t char = %p\n\t int = %p\n\t double = %p\n\t void = %p\n", cp, ip, dp, vp);
// Размеры указателей и памяти разыменованных указателей:
printf("\n\t The dimension of the object type \"pointer\":\n\t char = %d\n\t int = %d\n\t double = %d\n\t void = %d\n",
sizeof(cp), sizeof(ip), sizeof(dp), sizeof(vp));
printf("\n\t The size of the memory pointer:\n\t char = %d\n\t int = %d\n\t double = %d\n",
sizeof(*cp), sizeof(*ip), sizeof(*dp));
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.6.
(рис 7.6) Адреса и размеры указателей разных типовКак видно из полученного результата, размеры участков памяти, выделенных указателям разных типов, одинаковы.
void.d = 6.78.Пример 7. Напишите программу, в которой с помощью указателя и функции scanf_s() читаются данные с клавиатуры, а также определяются и инициализируются указатели на константы и константные указатели.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
int main (void) {
double x,
*px = x,
e = exp(1);
const double pi = acos(0.0);
const double *pexp = e;
const int base = 10;
const int *const pbase = base;
const double *ptr_pi = pi;
int i;
time_t t;
printf("\n Enter a real number: ");
scanf_s("%lf", px);
printf("\n The value of the entered number is \"%g\"\n", x);
printf("\n The base of natural logarithms \
is \"%0.14f\"\n", *pexp);
printf("\n The base of the decimal logarithm is \"%d\"\n",\ *pbase);
srand((unsigned) time(t)); // рандомизация
for (i = 0; i < rand(); i++)
{
rand();
}
// Случайное вещественное число из интервала [-100.0; 100.0]
x = -100.0 + (100.0 - (-100.0))* (double)rand() / RAND_MAX;
printf("\n The modified value of x: %g\n \
Pointer to the variable x: %g\n", x, *px);
printf("\n The value of pi through the pointer \
and the function acos(0): %0.14f\n", *ptr_pi * 2);
printf("\n\n ... Press any key: ");
_getch();
return 0;
}
В программе для получения числа пи ( $$\pi$$ ) используется функция , так как косинус $$\pi$$ /2 равен нулю. Затем полученный результат умножается на два. Дополнительная рандомизация осуществляется в цикле, одним из параметров которого является случайная функция rand(), возвращающая целое число. При этом предусмотрено приведение типов. Изменение числа х осуществляется по равномерному случайному закону из интервала [-100.0; 100.0].
Возможный результат выполнения программы показан на рис 7.7.
(рис 7.7) Пример работы программы с указателямиЗадание 7
NULL?По краткому определению, указатель – это переменная, содержащая адрес другой переменной [7.1]. Так как указатель содержит адрес переменной (объекта), это дает возможность "косвенного" доступа к этой переменной (объекту) через указатель.
Для понимания работы и назначения указателей рассмотрим упрощенную схему организации памяти компьютера. Память представляет собой массив последовательно пронумерованных или адресованных ячеек, с которыми можно работать по отдельности или связанными кусками. Известно, что различным типам данных отводится определенное количество байтов памяти. Поэтому указатель – это группа ячеек, в которых может храниться адрес. Например, если переменная ch имеет тип char, а ptr (от латинского pointer – указатель) есть указатель на переменную ch, то взятие адреса переменной ch осуществляется с помощью унарного (одноместного) оператора , т.е.
ptr = ch;
Приведенная инструкция означает, что переменной ptr присваивается адрес ячейки ch. Принято считать, что ptr указывает на ch. Оператор применяется только к объектам, расположенным в памяти: к переменным, элементам массива. Операндом оператора не может быть ни выражение, ни константа, ни регистровая переменная [7.1]. называется еще оператором адресации [7.2].
Имена указателям даются в соответствии с правилами, принятыми в языке программирования С для обычных переменных.
Другая унарная операция * называется операцией ссылки по указателю ( indirection ), или разыменования ( dereferencing ). Если применить ее к указателю, то получим объект, на который он указывает. Рассмотрим пример. Пусть х и у – целые переменные, а *ptr – указатель на целую переменную. Поставим задачу присвоения переменной у значения переменной х с помощью указателя. Фрагмент С -кода будет следующий:
int x = 1, y = 2; int *ptr; // объявили указатель на целую переменную ptr = x; // взяли адрес переменной х = 1 y = *ptr; // переменная у стала равной 1 *ptr = 0; // переменная х стала равной 0
В приведенных объявлениях новым является объявление указателя:
int *ptr;
Следует помнить, что любой указатель может указывать только объекты одного конкретного типа данных, заданного при объявлении [7.1].
* есть оператор косвенного доступа. Примененный к указателю он выдает объект, на который данный указатель указывает.
Одноместные (унарные) операции * и имеют более высокий приоритет для своих операндов, чем арифметические операции.
Для указателей одного типа можно, например, выполнять присваивание без разыменования. Это вытекает из того, что указатели сами по себе являются переменными. Пусть определен еще один указатель типа int, например, ptr2.
Тогда возможно произвести присвоение:
ptr2 = ptr;
После присвоения указатель ptr2 будет указывать на ту же переменную, что и указатель ptr.
В языке С допустимы следующие (основные) операции над указателями: присваивание; получение значения того объекта, на который ссылается указатель (синонимы:
С помощью унарных операций "++" и "––" числовые (арифметические) значения переменных типа указатель меняются по-разному в зависимости от типа данных, с которыми связаны эти переменные [7.3]. Если указатель связан с типом char, то при выполнении операций "++" и "––" его числовое значение изменяется на 1 (единицу). Если указатель связан с типом int, то операции "++" и "––" изменяют числовые значения указателей на 2. Указатель, связанный с типами float или long, унарными операциями "++" и "––" изменяется на 4. Таким образом, при изменении указателя на единицу указатель "переходит к началу" следующего (или пр
едыдущего) поля той длины, которая определяется типом.
Следует особо остановиться на указателях и квалификаторе (модификаторе) const. Как известно, квалификатор const превращает переменную в константу, значение которой не должно меняться. Например, нет смысла изменять число $$\pi$$. Значение константы должно быть инициализировано в месте ее определения. В связи с этим различают указатели на константы и константные указатели [7.6]. Приведем следующий пример:
long value = 9999L; const long *pvalue = value;
Последняя строчка приведенного кода определяет собой указатель на константу. Попытка указателю pvalue присвоить иное числовое значение будет восприниматься компилятором как ошибка [7.6]. Но само значение переменной value изменять допустимо. При этом указатель держит адрес переменной, значение которой изменилось. В тоже время саму переменную также можно объявить с помощью квалификатора const. В этом случае нельзя изменять ни переменную, ни значение указателя (т. е. присвоить иное числовое значение указателю). Указатели на константы часто используются как формальные параметры функций (о функциях будет сказано позднее).
Константный указатель может адресовать как константу, так и переменную. В случае, когда определен константный указатель, то через него нельзя уже брать адрес другой переменной. Приведем следующий пример определения константного указателя:
int count = 43; int *const pcount = count;
Вторая строчка приведенного кода определяет и инициализирует константный указатель pcount, который "привязан" к адресу переменной count. Если определить новую переменную того же типа, то взять адрес новой переменной с помощью константного указателя pcount будет нельзя, компилятор сделает сообщение об ошибке и работа программы будет невозможной. В тоже время возможно изменить значение константного указателя через другое числовое значение. Но это повлечет за собой изменение переменной, на которую указатель ссылается. Например,
int count = 43; int *const pcount = count; *pcount = 345;
В соответствии с приведенным кодом переменная count будет иметь значение 345 [7.6].
Соответственно, если константный указатель ссылается на константный объект (например, на константную переменную), то в этом случае ни значение объекта, на который ссылается такой указатель, ни значение самого указателя (когда будет сделана попытка присвоить иное числовое значение указателю) не может быть изменено в программе. Например,
const int card = 21; const int *const pcard = card
Указанные особенности для указателей с квалификатором const присущи и для переменных (объектов) других типов.
Указатели, значения которых изменять нельзя используются, например, при заполнении константных таблиц.
Пример 1. Напишите программу определения адресов целых чисел от 0 до 9 и строчных букв латинского алфавита.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void)
{
int i,
j = 0;
char c = 'a',
*ptr2;
ptr2 = c;
printf("\n\t Figures, symbols and their addresses:\n");
for (i = 0; i < 10; ++i)
printf("\n\t %3d) %2d --> %5p", i + 1, i, i);
printf("\n");
for ( ; *ptr2 <= 'z'; (*ptr2)++)
printf("\n\t %3d) %2c --> %5p", ++j, *ptr2, ptr2);
printf("\n\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.1.
(рис 7.1) Адреса цифр и строчных буквВ программе использован спецификатор формата %5p для определения
Задание 1
for примените операторы while.int и применить этот указатель по аналогии с указателем *ptr2.Пример 2. Напишите программу однозначного задания типа разностей указателей, и определения адресов заданных указателей.
Для решения данного примера подключим заголовок stddef.h для определения типа разности указателей с помощью зарезервированного имени типа ptrdiff_t.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
#include <stddef.h>
int main (void)
{
int x, y;
int *px, *py;
ptrdiff_t z;
// инициализация указателей
px = x;
py = y;
// разница двух указателей
z = px - py;
printf("\n The difference of two pointers to %p and %p is: %d", px, py, (int) z);
printf("\n\n The addresses are: px = %p, py = %p\n", px, py);
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.2.
(рис 7.2) Адреса указателей типа int и их разность
Задание 2
х и у. Проанализируйте результат выполнения программы.char, long int, long long int, unsigned int, float, double, long double.printf().Пример 3. Напишите программу арифметических операций с указателями.
При выполнении примера следует иметь в виду, что операции "" и "*" имеют более высокий приоритет, чем обычные арифметические операции. Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
int x = 2, y = 7, a, b, *ptr, *ptr2;
ptr = a;
ptr2 = b;
*ptr = x - y;
*ptr2 = y - x - *ptr + 100;
printf("\n\t Arithmetic operations with pointers:\n");
printf("\t a = %d, b = %d\n", a, b);
printf("\n Press any key: ");
_getch();
return 0; }
Результат выполнения программы показан на рис 7.3.
(рис 7.3) Результат арифметических операций с указателямиСледует обратить внимание на то, что переменные a и b сначала не были определены, а в результате стали иметь некоторые значения.
Задание 3
double и float.a и b, измените значения указателей на значения Х и 10*Х, где Х – номер компьютера, за которым выполняется лабораторная работа. Выполните указанные арифметические действия и выведите значения переменных a и b.printf().Пример 4. Напишите программу двухуровневой адресации для объектов целого типа.
Случай, когда указатель ссылается на указатель, который ссылается на число, называется многоуровневой адресацией [7.4]. В случае двухуровневой адресации первый указатель содержит адрес второго указателя, который содержит адрес объекта с нужным значением. Объявление указателя на указатель делается с помощью двух звездочек перед именем переменной. Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
int x, y = 8;
int *ptr, **ptr2;
x = 7;
ptr = x;
ptr2 = ptr;
**ptr2 = *ptr + 10;
printf("\n\t The value of x = %d. 1-st pointer is: %d. 2-nd pointer is: %d\n", x, *ptr, **ptr2);
ptr = y;
ptr2 = ptr;
**ptr2 = 88;
printf("\n\t The value of y = %d\n", y);
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.4.
(рис 7.4) Результат двухуровневой адресацииЗадание 4
Пример 5. Напишите программу по определению и инициализации переменных разных типов и одного указателя типа void *. Последовательно присваивая указателю
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void){
int x = 99;
double y = 6.78;
char symbol = '#';
void *ptr;
ptr = x;
printf("\n\t The value of variable through a pointer: %d\n", *(int *) ptr);
ptr = y;
printf("\n\t The value of variable through a pointer: %lf\n", *(double *) ptr);
ptr = symbol;
printf("\n\t The value of variable through a pointer: %c\n", *(char *) ptr);
printf("\n Press any key: ");
_getch();
return 0;}
Результат выполнения программы показан на рис 7.5.
(рис 7.5) Результат настройки указателя типа void
Особенностью использования указателя типа void является то, что при
Задание 5
float, unsigned, long и обеспечьте ввод их значений с клавиатуры. Выведите адреса и значения переменных с помощью разыменования указателя.void. Выведите значения двух указателей с помощью их разыменования.Пример 6. Напишите программу по реализации условия: определить и инициализировать переменную типа double. Определите указатели типа char *, int *, double *, void *, инициализируйте их адресом переменной. Выведите на экран пользователя значения указателей, их размеры и длины участков памяти, которые связаны с выражениями, разыменовывающими указатели [7.5].
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
int main (void) {
double d = 6.78;
char *cp;
int *ip;
double *dp;
void *vp;
// Адресация с приведением типов
cp = (char *)d;
ip = (int *)d;
dp = (double *)d;
vp = d;
printf("\n\t Address:\n\t char = %p\n\t int = %p\n\t double = %p\n\t void = %p\n", cp, ip, dp, vp);
// Размеры указателей и памяти разыменованных указателей:
printf("\n\t The dimension of the object type \"pointer\":\n\t char = %d\n\t int = %d\n\t double = %d\n\t void = %d\n",
sizeof(cp), sizeof(ip), sizeof(dp), sizeof(vp));
printf("\n\t The size of the memory pointer:\n\t char = %d\n\t int = %d\n\t double = %d\n",
sizeof(*cp), sizeof(*ip), sizeof(*dp));
printf("\n Press any key: ");
_getch();
return 0;
}
Результат выполнения программы показан на рис 7.6.
(рис 7.6) Адреса и размеры указателей разных типовКак видно из полученного результата, размеры участков памяти, выделенных указателям разных типов, одинаковы.
void.d = 6.78.Пример 7. Напишите программу, в которой с помощью указателя и функции scanf_s() читаются данные с клавиатуры, а также определяются и инициализируются указатели на константы и константные указатели.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
int main (void) {
double x,
*px = x,
e = exp(1);
const double pi = acos(0.0);
const double *pexp = e;
const int base = 10;
const int *const pbase = base;
const double *ptr_pi = pi;
int i;
time_t t;
printf("\n Enter a real number: ");
scanf_s("%lf", px);
printf("\n The value of the entered number is \"%g\"\n", x);
printf("\n The base of natural logarithms \
is \"%0.14f\"\n", *pexp);
printf("\n The base of the decimal logarithm is \"%d\"\n",\ *pbase);
srand((unsigned) time(t)); // рандомизация
for (i = 0; i < rand(); i++)
{
rand();
}
// Случайное вещественное число из интервала [-100.0; 100.0]
x = -100.0 + (100.0 - (-100.0))* (double)rand() / RAND_MAX;
printf("\n The modified value of x: %g\n \
Pointer to the variable x: %g\n", x, *px);
printf("\n The value of pi through the pointer \
and the function acos(0): %0.14f\n", *ptr_pi * 2);
printf("\n\n ... Press any key: ");
_getch();
return 0;
}
В программе для получения числа пи ( $$\pi$$ ) используется функция , так как косинус $$\pi$$ /2 равен нулю. Затем полученный результат умножается на два. Дополнительная рандомизация осуществляется в цикле, одним из параметров которого является случайная функция rand(), возвращающая целое число. При этом предусмотрено приведение типов. Изменение числа х осуществляется по равномерному случайному закону из интервала [-100.0; 100.0].
Возможный результат выполнения программы показан на рис 7.7.
(рис 7.7) Пример работы программы с указателямиЗадание 7
NULL?Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.