Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Практическая часть. Пример 1. Напишите программу определения адресов целых чисел от 0 до 9 и строчных букв латинского алфавита.






Пример 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;

}

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

Рис. 9.1. Адреса цифр и строчных букв

В программе использован спецификатор формата %5p для определения адреса переменных. Число 5 определяет отступ от левого края на пять позиций.

Пример 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;

}

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

Рис. 9.2.

Пример 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; }

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

Рис. 9.3. Результат арифметических операций с указателями

Следует обратить внимание на то, что переменные a и b сначала не были определены, а в результате стали иметь некоторые значения.

Пример 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;

}

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

Рис. 9.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; }

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

Рис. 9.5.

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

Пример 6. Напишите программу по реализации условия: определить и инициализировать переменную типа double. Определите указатели типа char *, int *, double *, void *, инициализируйте их адресом переменной. Выведите на экран пользователя значения указателей, их размеры и длины участков памяти, которые связаны с выражениями, разыменовывающими указатели.

Программный код решения примера:

#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;

}

 

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

Рис. 9.6. Адреса и размеры указателей разных типов

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

Пример 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;

 

}

В программе для получения числа пи (π) используется функция acos(0), так как косинус π /2 равен нулю. Затем полученный результат умножается на два. Дополнительная рандомизация осуществляется в цикле, одним из параметров которого является случайная функция rand(), возвращающая целое число. При этом предусмотрено приведение типов. Изменение числа х осуществляется по равномерному случайному закону из интервала
[-100.0; 100.0].

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

Рис. 9.7. Пример работы программы с указателями

Пример 8. Напишите программу сортировки одномерного массива, состоящего из 10 равномерно распределенных случайных чисел из интервала [–8; 8], с помощью указателей.

Программный код решения примера:

#include < stdio.h> #include < conio.h> #include < stdlib.h> #include < time.h> #define N 10 int main (void) { double a = -8.0, b = 8.0; double arr[N], *pmin[N], *temp; int i, j; long int T; T = (long)time(NULL); // использование системного времениsrand((unsigned int) T); // Заполнение массива случайными числами for(i = 0; i < N; ++i) arr[i] = a + (b - a)*(double)rand()/RAND_MAX; printf(" \n\t The initial array of [%1.4f, %1.4f]: \n", a, b); for (i = 0; i < N; ++i) printf(" \n\t%2d) %8.4f", i+1, arr[i]); // Взятие адресов элементов исходного массива//в предположении, что они образуют отсортированный массив for (i = 0; i < N; ++i) pmin[i] = & arr[i]; //Сортировка массива по убываниюfor (i = 0; i < N-1; ++i) for (j = i+1; j < N; ++j) { if (*pmin[i] < *pmin[j]) {temp = pmin[i]; pmin[i] = pmin[j]; pmin[j] = temp; }} //Вывод отсортированного массива по убываниюprintf(" \n\n\t Assorted array of descending: \n"); for (i = 0; i < N; ++i)printf(" \n\t%2d) %8.4f", i+1, *pmin[i]); printf(" \n\n Press any key: "); _getch(); return 0; }

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

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

Рис. 9.8. Сортировка массива по убыванию

Пример 9. Напишите программу заполнения матрицы по спирали натуральными числами с помощью массива указателей.

Программный код решения примера:

#include < stdio.h> #include < conio.h> #define n 15 int main(void) {int i = 1, I, j, k, p = n/2; int M[n][n], *ptr[n*n]; // Обнуление матрицы и инициализация указателяfor (I = 0; I < n; ++I)for (j = 0; j < n; ++j){ M[I][j] = 0; ptr[I*n + j] = & M[I][j]; } for (k = 1; k < = p; k++) // Число спиралей{// Верхний горизонтальный столбецfor (j = (k-1); j < (n-k+1); j++)*ptr[(k-1)*n + j] = i++; // Правый верхний столбецfor (j = k; j < (n-k+1); j++) *ptr[j*n + (n-k)] = i++; // Нижний горизонтальный столбецfor (j = (n-k-1); j > = (k-1); --j) *ptr[(n-k)*n + j] = i++; // Левый верхний столбецfor (j = (n-k-1); j > = k; j--) *ptr[j*n + (k-1)] = i++; }if (n % 2) *ptr[p*n + p] = n*n; printf(" \n\t Spiral matrix of dimention (%d x %d): \n\n", n, n); for (i = 0; i < n; ++i)for (j = 0; j < n; ++j){ if (n*n < 20*20){ printf(" %4d", *ptr[i*n + j]); if (j == (n-1)) printf(" \n"); } else if (n*n > = 20*20) goto mes; } mes: if (n > 19)printf(" \n\t It is a large matrix. Can not to see on display.\n"); printf(" \n Press any key: "); _getch(); return 0; }

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

Рис. 9.9. Заполнение матрицы по спирали

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

Примечание. Сумма диагональных элементов квадратной матрицы называется следом (шпуром) матрицы.

Пример 10 Напишите программу заполнения целочисленной прямоугольной матрицы размером не более 15× 14 из интервала [–12; 12] с помощью операции разыменования.

Программный код решения примера:

#include < stdio.h> #include < conio.h> #include < stdlib.h> #include < time.h> #define N 15#define M 14const int Left = -12; const int Right = 12; int main(void) {int i, j, n, m; int matr[N][M]; time_t t; //переменная системного времени srand((unsigned)time(& t)); printf(" \n Enter the number of lines of the matrix is not more than %d: ", N); scanf_s(" %d", & n); printf(" Enter the number of columns of the matrix is not more than %d: ", M); scanf_s(" %d", & m); // Контроль ввода допустимой размерностиif (n > N || m > M || n < 1 || m < 1){ printf(" \n\t Data error! Repeat please.\n"); printf(" \n Press any key: "); _getch(); return 0; } for (i = 0; i < n; ++i)for (j = 0; j < m; ++j)*(*(matr + i) + j) = 0; for (i = 0; i < n; ++i)for (j = 0; j < m; ++j)*(*(matr + i) + j) = (rand() % (2*Right+1)) + Left; printf(" \n The matrix of random whole numbers from the entire [%d, %d]: \n", Left, Right); for (i = 0; i < n; ++i) {printf(" \n "); for (j = 0; j < m; ++j)printf(" %5d", *(*(matr + i) + j)); } printf(" \n\n Press any key: "); _getch(); return 0; }

В программе использованы спецификаторы const для объявления неизменяемых переменных. Функция srand() устанавливает начальное значение программного генератора псевдослучайных чисел, т.е. осуществляет рандомизацию последовательности псевдослучайных чисел. С этой целью определена системная переменная time(& t), которая практически всегда различна.

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

Рис. 9.10. Матрица случайных целых чисел

Контрольные вопросы

  1. Какое общее назначение указателей в языке С?
  2. Какие арифметические операции допускаются для указателей?
  3. Какие унарные операторы используются с указателями? Как они называются?
  4. Для каких типов данных может быть использован указатель?
  5. Как числовые значения указателей изменяются при их инкрементировании в зависимости от типов данных.
  6. С помощью какого формата осуществляется вывод на консоль адресов переменных заданного типа?
  7. Что такое многоуровневая адресация? Как она организуется в языке С?
  8. Как осуществляется инициализация указателей на вещественные типы данных?
  9. Как осуществляется инициализация указателей на символьный тип данных?
  10. Какой смысл имеет значение указателя NULL?
  11. Что произойдет, если применить к указателю со значением NULL операцию разыменования?
  12. Как следует определять и инициализировать указателя на константу?
  13. Как следует определять и инициализировать константный указатель?
  14. Какое отличие константного указателя от указателя на константу?
  15. Как рассматривает имя массива компилятор языка С?
  16. На какое место в памяти компьютера указывает имя массива?
  17. Какая связь между указателями и массивами в языке С?
  18. Как формируется массив указателей в языке С?
  19. Как следует организовать посимвольное формирование строки символов с помощью указателя?
  20. Как с помощью одного указателя произвести инициализацию и вывод результата на консоль двухмерного (трехмерного) числового массива?
  21. Как изменяется значение типизированного указателя при применении к нему операции адресного сложения?
  22. Как производится вычитание указателей?





© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.