- •1 Понятие алгоритма формы представления алгоритмов
- •2 Линейные и разветвляющиеся алгоритмы.
- •3 Циклические алгоритмы
- •4 Понятие прикладного и системного программирования
- •5 Структура программ на языке си
- •6 Арифметико-логические операции над переменными
- •Арифметические операции
- •Операции увеличения и уменьшения
- •Операции "увеличить на", "домножить на" и т.П.
- •Логические операции
- •Операции сравнения
- •Побитовые логические операции
- •7 Два вида оператора выбора Оператор if
- •8 Понятие цикла
- •1.4.6. Оператор break
- •1.4.7. Оператор for
- •1.4.8. Оператор while
- •1.4.9. Оператор do while
- •1.4.10. Оператор continue
- •1.4.11. Оператор return
- •9 Массив
- •12 Указатели
- •13 Адресная арифметика
- •14 Операции над указателями
- •15 Массивы указателей
- •16 Указатели на функции Указатели на функции
- •17 Структуры
- •18 Доступ к элементам структуры
- •19 Структуры как аргументы
- •6.2. Структуры и функции
- •20 Динамические структуры на массиве
- •21 Динамическое распределение памяти Функции динамического распределения
- •Динамическое выделение памяти для массивов
- •23 Организация доступа к файлам
- •Закрытие потока при помощи fclose
- •Чтение из потока при помощи fgetc
- •«Ловушка» eof
- •При помощи fgets
- •24 Форматированный ввод –вывод Функции форматированного ввода и вывода в си
- •Спецификатор типа
- •Спецификатор типа
- •25 Верификация тестирование отладка программ
- •Введение
- •26 Причины и последствия появления ошибок
- •27 Идея модульного программирования
- •28 Технология проектирования сверху-вниз
- •29 Итерация рекурсия
- •30 Методы сортировки
- •34 Способы защиты информации
14 Операции над указателями
Над указателями определено 5 основных операций.
Определение адреса указателя: &p, где p – указатель (&p – адрес ячейки, в которой находится указатель).
Присваивание. Указателю можно присвоить адрес переменной p=&q, где p – указатель, q – идентификатор переменной.
Определение значения, на которое ссылается указатель: *p (операция косвенной адресации).
Увеличение (уменьшение) указателя. Увеличение выполняется как с помощью операции сложения (+), так и с помощью операции инкремента (++). Уменьшение – с помощью операции вычитания (–) либо декремента (––).
Например, пусть p1 – указатель, тогда р1++ перемещает указатель на:
o 1 байт, если *p1 имеет тип char;
o 4 байта, если *p1 имеет тип int (в 32 разрядной операционной системе) или 2 байта (в 16 разрядной операционной системе);
o 4 байта, если *p1 имеет тип float.
Разность двух указателей. Пусть р1 и р2 – указатели одного и того же типа. Можно определить разность р1 и р2, чтобы найти, на каком расстоянии друг от друга находятся элементы массива.
Пример программы.
Даны адреса переменных &a=63384,&b=64390,&c=64404. Что напечатает ЭВМ?
# include <stdio.h>
int main()
{
float a,*p1;
int b,*p2;
char c,*p3;
a=2.5; b=3; c='A';
p1=&a; p2=&b; p3=&c;
p1++; p2++; p3++;
printf("\n p1=%u, p2=%u, p3=%u",p1,p2,p3);
return 0;
}
Ответ: р1=63388, р2=64392, р3=64405.
15 Массивы указателей
Указатели и массивы
Массив – это набор пронумерованных однотипных данных.
Синтаксис определения массива:
спецификатор_типа array[константное_выражение];
В определении массива array – имя массива, константное_выражение – ко-
личество элементов в массиве, спецификатор_типа – тип элементов в масси-
ве. Все элементы массива пронумерованы, начиная с нуля.
При определении массива его элементы можно инициализировать сле-
дующим образом:
спецификатор_типа array[ ]={ значение1,значение2, …, значениеN };
В фигурных скобках { } через запятую перечисляются значения элемен-
тов массива соответствующего типа.
В языке СИ между указателями и массивами существует некоторая связь.
Когда объявляется массив, то его имя отождествляется с константой, значение
которой равно адресу нулевого элемента массива.
Пример определения и использования массива.
int array[5]={2, 8, 45, 16, 12}; /* Определение и инициализация массива */
int *ptr; /* Определение указателя */
ptr=&array[0]; /* Присваивание адреса нулевого элемента массива
указателю ptr */
Указатель ptr устанавливается на адрес нулевого элемента масcива, при-
чем присваивание ptr=&array[0] можно записать в эквивалентной форме
ptr=array.
Между именем массива и указателем, выступающим в роли имени масси-
ва, существует важное различие. Указатель – это переменная, поэтому допус-
тима операция изменения ее значения: ptr=array или ptr++. Но имя массива не
является переменной, и записи типа array =ptr или array++ ошибочны.
Многомерные массивы так же часто используются, как и одномерные. Вот примеры: в школьных журналах написаны Фамилия и класс; любые базы данных; Вообще, многомерные массивы - это массивы массивов. Т.е. каждый индексный номер содержит массив. Вот пример уже из языка Си:
int i[2][4] = {{1,2,3,4}, {5,6,7,8}};
Т.е. тут мы создаем двумерный массив размером 2х4. Т.е. 2 строчки по 4 элемента каждая. В принципе, остальное тут так же. Давайте теперь рассмотрим, как в многомерном массиве вводить и выводить элементы:
#include <conio.h> #include <stdio.h> int main() { int arr[2][4]; for (int i = 0; i < 2; i++){ for (int j = 0; j < 4;j++ ){ scanf ("%d", &arr[i][j]); } } for (int i = 0; i < 2; i++){ for (int j = 0; j < 4;j++ ){ printf ("%d ", arr[i][j]); } printf ("\n"); } getch(); return 0; }
Все очень похоже на одномерный массив. Только в многомерном массиве мы создаем двойной цикл, первый - это проход по столбцу, а второй - это проход по элементам массива (идем по строке). Во всех моих примерах при изменении размера многомерного массива, например вместо arr[2][4], хочу сделать arr[7][6]. Так вот, что бы сделать такое изменения придется изменять абсолютно все циклы, так как они ориентируются по старым данным. Но есть способ исправить эту проблему. Для этого в языке С/C++ есть директива предпроцессора define. Давайте рассмотрим его на примере:
#include <conio.h> #include <stdio.h> #define SIZE_A 2 #define SIZE_B 2 int main() { int arr[SIZE_A][SIZE_B]; for (int i = 0; i < SIZE_A; i++){ for (int j = 0; j < SIZE_B;j++ ){ scanf ("%d", &arr[i][j]); } } for (int i = 0; i < SIZE_A; i++){ for (int j = 0; j < SIZE_B;j++ ){ printf ("%d ", arr[i][j]); } printf ("\n"); } getch(); return 0; }
Т.е. мы можем поменять значения только в одном месте, и они автоматом поменяются во всех остальных местах. Причем подстановка будет происходить на этапе компиляции Осталось научиться передавать многомерные массивы в функцию. Вот как это делается:
void printArr (int arr[][2]){ //тело; }
Тут обязательным условием является написание во втором индексе количества элементов, иначе компилятор выдаст ошибку. Ах да, вызывается функция из программы, так же как и одномерный массив:
printArr(arr);
Вот и все, что хотелось вам рассказать о многомерных массивах. Лучше всего любой материал по программированию запоминается на практике.