- •Структура программы на языке Си. Этапы выполнения программы
- •1.1. Алфавит языка Си
- •1.2. Лексемы
- •1.3. Идентификаторы и ключевые слова
- •1.4. Знаки операций
- •1.5. Литералы (константы)
- •1.6. Комментарии
- •1.7. Общая структура программы на языке Си.
- •1.8. Функциональная и модульная декомпозиции
- •1.9. Этапы обработки программы.
- •1.10. Роль препроцессора.
- •1.11. Ошибки
- •2. Переменные и константы. Типы данных
- •2.1. Основные типы данных
- •2.2. Декларация (объявление) объектов
- •2.3. Константы в программах
- •2.4. Целочисленные константы
- •2.5. Константы вещественного типа
- •2.6. Символьные константы
- •2.7. Строковые константы
- •3. Обзор операций
- •3.1. Операции, выражения
- •3.2. Арифметические операции
- •3.3. Операции сравнения
- •3.4. Логические операции
- •4. Операции (продолжение).
- •4.1. Операция присваивания
- •Примеры недопустимых выражений:
- •4.2. Сокращенная запись операции присваивания
- •4.3. Преобразование типов операндов бинарных операций
- •4.4. Преобразование типов при присваивании.
- •4.5. Операция явного приведения типа
- •4.6. Операция «,» (запятая)
- •5. Стандартная библиотека языка Си
- •5.1. Стандартные математические функции
- •5.2. Потоковый ввод-вывод
- •5.3. Консольные функции вывода данных на экран
- •5.4. Консольные функции ввода информации
- •5.5. Ввод-вывод в оконных приложениях.
- •Советы по программированию
- •6. Операторы языка с.
- •7. Составление разветвляющихся алгоритмов
- •7.1. Условные операторы
- •If (выражение) оператор;
- •If (выражение) оператор 1 ;
- •If (выражение 1) оператор 1;
- •If (выражение 2) оператор 2;
- •If (выражение 3) оператор 3;
- •7.2. Оператор выбора альтернатив (переключатель)
- •7.3. Условная операция «? :»
- •8. Составление циклических алгоритмов
- •8.1. Оператор с предусловием while
- •8.2. Оператор цикла с постусловием do – while
- •8.3. Оператор цикла с предусловием и коррекцией for
- •8.4. Вложенные циклы.
- •9. Операторы передачи управления.
- •9.1. Оператор безусловного перехода goto
- •9.2. Операторы continue, break и return
- •10. Массивы
- •10.1. Одномерные массивы
- •10.2. Примеры алгоритмов, использующих одномерные массивы.
- •10.3. Многомерные массивы
- •10.4. Примеры алгоритмов, использующих двумерные массивы.
- •10.5. Компонента StringGrid
- •11. Размещение данных и программ в памяти пэвм
- •11.1. Общие понятия.
- •11.2. Кодирование целых чисел.
- •11.3. Кодирование вещественных чисел.
- •11.4. Кодирование символов.
- •Примеры кодов символов:
- •Стандартная часть таблицы символов (ascii)
- •Дополнительная часть таблицы символов
- •11.5. Операция sizeof
- •11.6. Побитовые логические операции. Операции над битами
- •11.7. Кодирование программы.
- •11.8. Регистры
- •12.1. Строки как нуль-терминированные массивы char.
- •12.2. Русификация консольных приложений.
- •12.3. Строки как переменные типа AnsiString.
- •12.4. Преобразования строковых типов.
- •12.5. Тип String в консольных приложениях.
- •13. Функции пользователя и классы памяти.
- •13.1. Сущность и предназначение функций.
- •13.2. Определение и вызов функции.
- •13.3. Прототип функции.
- •13.4. Область видимости.
- •13.5. Классы памяти объектов в языке Cи.
- •13.6. Разбиение программы на модули.
- •14. Структуры и объединения
- •14.1. Понятие структуры
- •14.2. Декларация структурного типа данных
- •14.3. Объявление структурных переменных
- •14.4. Обращение к полям структуры
- •14.5. Операции со структурой как единым целым
- •14.6. Вложенные структуры
- •14.7. Массивы структур
- •14.8. Размещение структурных переменных в памяти
- •14.9. Битовые поля
- •14.10. Объединения
- •15. Генерация псевдослучайных чисел.
- •16. Файлы в языке с
- •16.1. Типы файлов.
- •16.2. Открытие файла
- •16.3. Закрытие файла
- •16.4. Запись - чтение информации
- •А) Посимвольный ввод-вывод
- •Б) Построчный и форматированный ввод-вывод
- •В) Блоковый ввод-вывод
- •Int fflush(file *stream);
- •16.5. Текстовые файлы
- •16.6. Перенаправление стандартного ввода-вывода
- •16.7. Бинарные файлы
- •16.8. Дополнительные полезные функции
- •16.9. Простейший пример создания собственной базы данных
- •17. Указатели
- •17.1. Определение указателей
- •17.2. Связь указателей и массивов.
- •17.3. Операции над указателями (косвенная адресация)
- •17.4. Операции над указателями (косвенная адресация)
- •17.5. Массивы указателей.
- •17.6. Указатели на указатели.
- •17.7 . Указатели как параметры функций.
- •Void f1(int, const double *);
- •17.8 . Указатели на структуры
- •17.9. Ссылка
- •17.10. Указатели на функции
- •Id_функции(список аргументов);
- •18. Работа с динамической памятью
- •18.1. Динамическое выделение и освобождение памяти.
- •18.2. Создание одномерного динамического массива.
- •18.3. Создание двуxмерного динамического массива.
- •19. Операция typedef
- •20. Отладка и пошаговое выполнение программы
10. Массивы
Массив представляет собой упорядоченную конечную совокупность элементов одного типа. Число элементов массива называют его размером. Каждый элемент массива определяется идентификатором (именем) массива и своим порядковым номером – индексом. Индекс – целое число, по которому производится доступ к элементу массива.
Индексов может быть несколько. В этом случае массив называют многомерным, а количество индексов одного элемента массива называется его размерностью.
Массивы нужны тогда, когда требуется произвести одни и те же действия над многими числами, и притом эти числа должны храниться в памяти одновременно. Поэтому для работы с массивами, как правило, используются циклы, перебирающие элементы массива.
Описание массива в программе отличается от описания простой переменной наличием после имени квадратных скобок, в которых задается количество элементов массива. Например, double b[10]; – описание массива из 10 вещественных чисел.
10.1. Одномерные массивы
В программе одномерный массив объявляется следующим образом:
тип ID_массива [размер] = {список начальных значений};
тип – тип элементов массива;
размер – количество элементов в массиве.
Список начальных значений используется при необходимости задать начальные значения (инициализировать элементы массива), он может отсутствовать. Значения в списке разделяются запятыми. (Такое задание списка элементов массива допустимо только при его инициализации и недопустимо в операции присваивания).
Примеры объявления массива:
int a[6];
double x[5]={2, 3.5, -4.5e3, 2.34, -.7 };
Если в группе {…} список значений короче, то оставшимся элементам присваивается 0.
Обращение к конкретному элементу массива в программе осуществляется путем записи имени массива и за ним в квадратных скобках - номера элемента, например:
a[0]=1;
a[i]++;
a[3]=a[i]+a[i+1];
Индексы массивов в языке Си начинаются с 0, т.е. в массиве x первый элемент: x[0], второй – x[1], … пятый – x[4].
Размер массива может задаваться только константой или константным выражением. Нельзя задавать массив переменного размера. Для этого существует отдельный механизм – динамическое выделение памяти.
С другой стороны, если требуемое количество элементов массива заранее неизвестно, часто объявляют массив достаточно большого размера, а используют лишь столько из его элементов, сколько нужно. При этом требуется переменная, задающая количество используемых в данный момент элементов массива:
int a[100], n, i;
M: cout<<"Vvedite kolichestvo elementov (ne bolshe 100)";
cin>>n;
if (n>100) goto M;
cout<<"Vvedite elementy:\n";
for (i=0; i<n; i++)
cin >> a[i];
Внимание. В языке Си с целью повышения быстродействия программы отсутствует механизм контроля выхода за границы индексов массивов. При необходимости такой механизм должен быть запрограммирован явно.
10.2. Примеры алгоритмов, использующих одномерные массивы.
а) Простейший пример
Задача 1. Ввести с клавиатуры массив, а затем вывести только его положительные элементы:
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void main()
{
int a[100],n,i;
M: cout<<"Vvedite n<=100:";
cin>>n;
if(n>100) goto M;
cout<<"Vvedite massiv:\n";
for (i=0; i<n; i++)
cin>>a[i];
cout<<"Polozhitelnye elementy: ";
for (i=0; i<n; i++)
if (a[i]>0)
cout<<a[i]<<" ";
cout<<endl;
getch();
}
б) Нахождение суммы, произведения, количества
Задача 2. Найти сумму элементов массива.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void main()
{
int a[100],n,i,s;
M: cout<<"Vvedite n<=100:";
cin>>n;
if(n>100) goto M;
cout<<"Vvedite massiv:\n";
for (i=0; i<n; i++)
cin>>a[i];
s=0;
for (i=0; i<n; i++)
s+=a[i];
cout<<"summa="<<s<<endl;
getch();
}
Задача 3. Найти сумму положительных элементов массива.
От предыдущей задачи она отличается только добавлением оператора if:
s=0;
for (i=0; i<n; i++)
if (a[i]>0)
s+=a[i];
Задача 4. Найти произведение положительных элементов массива.
Содержательный участок программы имеет вид:
s=1;
for (i=0; i<n; i++)
if (a[i]>0)
s*=a[i];
Задача 5. Найти количество положительных элементов массива.
s=0;
for (i=0; i<n; i++)
if (a[i]>0)
s++;
Задача 6. Найти сумму четных (по значению) элементов массива.
s=0;
for (i=0; i<n; i++)
if (a[i]%2==0)
s+=a[i];
в) Нахождение порядковых номеров элементов
Задача 7. Найти сумму четных (по порядковому номеру) элементов массива.
Поскольку индексы элементов считаются с 0, а порядковые номера - с 1, четный порядковый номер означает нечетный индекс:
s=0;
for (i=0; i<n; i++)
if (i%2==1)
s+=a[i];
Задача 8. Найти индексы отрицательных элементов массива.
for (i=0; i<n; i++)
if (a[i]<0)
cout<<i<<" ";
cout<<endl;
Задача 9. Найти индекс первого из отрицательных элементов массива.
for (i=0; i<n; i++)
if (a[i]<0) {
cout<<i<<endl;
break;
}
Задача 10. В массиве найти первый и последний нулевой элементы. Все элементы, лежащие между ними, увеличить на 1.
for (i=0; i<n; i++)
if (a[i]==0) {
cout<<i<<endl;
break;
}
for (k=n-1; k>=0; k--)
if (a[k]==0) {
cout<<k<<endl;
break;
}
for (p=i+1; p<k; p++)
a[p]++;
for (i=0; i<n; i++)
cout<<a[i]<<" ";
cout<<endl;
г) Проверка условия, относящегося к массиву.
Задача 11. Проверить, все ли элементы массива меньше 5.
Для этого достаточно подсчитать количество элементов, не меньших 5:
for (i=s=0; i<n; i++)
if (a[i]>=5)
s++;
if (s)
cout<<"Ne vse elementy men\'she 5 !";
Заметим, что s++ можно заменить на s=1, т.к. конкретное количество элементов здесь несущественно.
Таким образом, для проверки условия, относящегося к массиву в целом, обычно нужна дополнительная переменная и цикл.
д) Удаление и вставка в массивах
Задача 11. Удалить из массива второй по счету элемент.
Поскольку полное количество элементов в массиве задано в его объявлении, физически "удалить" элемент из массива невозможно. Но с практической точки зрения, "удалить" элемент можно путем "сдвига" всех следующих за ним элементов "влево" (т.е. на предыдущую позицию, с меньшим на 1 индексом) и уменьшения на 1 количества используемых элементов:
-
1
2
3
4
5
0
0
-
1
3
4
5
5
0
0
Здесь используемые элементы выделены жирным цветом, а неиспользуемые - бледным.
Фрагмент программы имеет вид:
for (i=2; i<n; i++)
a[i-1]=a[i];
n--;
Задача 12. Удалить из массива элементы, большие 10.
В этой задаче требуется удалить заранее неизвестное количество элементов; поэтому неясно, на сколькр позиций нужно производить сдвиг. Потому лучше просто ввести две разные переменные: индекс элемента "до сдвига" и его индекс "после".
Сдвинуть нужно все неудаляемые элементы. Их количество и будет новым числом используемых элементов массива.
Индекс "до сдвига", очевидно, принимает все значения от 0 до n-1. А индекс "после" увеличивается на 1 после каждой записи очередного элемента:
for (k=i=0; i<n; i++)
if (a[i]<=10) a[k++]=a[i];
n=k;
Задача 13. Вставить в массив число 5 на вторую по счету позицию.
Подобно удалению, "вставка элемента" по сути означает "сдвиг" части элементов массива "вправо" (т.е. на последующие позиции, с большими индексами) и помещение вставляемого числа на освободившуюся позицию. При этом число используемых элементов возрастает.
При программировании этого алгоритма нужно быть осторожным, чтобы не испортить последующие элементы массива раньше, чем они будут сдвинуты. Например, следующая программа:
for (i=0; i<n; i++)
a[i+1]=a[i];
n++;
заполнит все n элементов массива одним и тем же значением, равным первоначальному значению a[0]. Действительно, при первой итерации цикла i=0, и будет выполнено a[1]=a[0]. При второй итерации будет a[2]=a[1] (а значение a[1] уже равно a[0] ) и т.д.
Одним из выходов является использование второго массива:
b[0]=a[0];
b[1]=5;
for (i=1; i<n; i++)
b[i+1]=a[i];
n++;
for (i=0; i<n; i++)
a[i]=b[i];
Другой способ - изменить порядок сдвига:
for(i=n; i>1; i--)
a[i]=a[i-1];
a[1]=5;
n++;
е) Обмен местами
Задача 14. Поменять местами первый и последний элемент массива.
При обмене, чтобы не потерять одно из значений, потребуется дополнительная переменная:
p=a[0];
a[0]=a[n-1];
a[n-1]=p;
ж) Поиск минимума/максимума
Задача 15. Найти в массиве наименьший элемент и его позицию.
В подобных задачах нахождения "самого-" в каком-нибудь смысле элемента используется та же идея, что и в спорте при определении рекорда: каждый очередной результат сравнивается с текущим рекордом, и если он "лучше", то он и становится новым значением рекорда, а иначе рекорд не меняется. За начальное значение рекорда принимается первый результат.
min=a[0]; k=0;
for (i=0; i<n; i++)
if (a[i]<min)
{ min=a[i]; k=i; }
Эту же программу можно переписать и короче:
for (i=k=0, min=a[0]; i<n; i++)
if (a[i]<min)
min=a[k=i];
з) Сортировка массива
Задача 16. Отсортировать массив по возрастанию (т.е. расположить его элементы в порядке возрастания).
Для этой задачи придумано множество различных алгоритмов. Один из них - сортировка методом прямого выбора:
for(i=0; i<n; i++)
for(k=i+1; k<n; k++)
if (a[k]<a[i]) {
p=a[k]; // Обмен a[k] и a[i]
a[k]=a[i];
a[i]=p;
}
Здесь на каждой итерации внешнего цикла происходит помещение на i-ую позицию наименьшего из "оставшихся" (т.е. расположенных от i-ой позиции до конца массива) значений элементов.
Этот алгоритм включает в себя, таким образом, алгоритмы поиска минимума и обмена.
и) Поиск совпадений
Задача 17. Найти в массиве элемент, повторяющийся наибольшее количество раз. (Если таких элементов несколько, вывести любой из них).
for(max=i=0; i<n; i++){
s=1; // s - число повторений i-го элемента
for(k=i+1; k<n; k++)
if (a[k]==a[i]) s++;
if (s>max) {
max=s; // max - число повторений x
x=a[i]; // x - значение наиболее
} // частого элемента
}
Заметим, что x здесь не присвоено начальное значение, т.к. оператор x=a[i]; обязательно выполнится хотя бы раз (max вначале = 0, а s не меньше 1), а использовано x будет лишь впоследствии.