- •Московский государственный социальный университет академия информатики и информационных технологий
- •Введение
- •Часть. Основы программирования на Си
- •1.1. Структура простейшей Си-программы
- •1.2. Данные в Си и операции над ними
- •1.2.1. Свойства ячейки памяти. Переменные и константы
- •1.2.2. Типы данных в Си
- •1.2.3. Правила записи констант в Си
- •1.2.4. Описание переменных и именованных констант в Си.
- •1.2.5. Выражения в Си
- •1.3. Операторы преобразования данных
- •1.3.1. Общие положения
- •1.3.2. Функция форматного выводаprintf()
- •1.3.3. Функция форматного вводаscanf()
- •1.4. Разработка программ на Си
- •1.4.1. Понятие о качестве программы и основные технологические принципы разработки программ
- •1.4.2. Алгоритм и способы его записи.
- •1.4.3. Изображение алгоритмов в виде блок-схем
- •1.4.4. Базовые структуры алгоритмов и их кодирование на Си.
- •1. Следование
- •2. Разветвление (развилка)
- •If (условие)
- •If (условие)
- •3. Цикл
- •1.4.4. Примеры разработки программ
- •1.5. Массивы и указатели
- •1.5.1. Понятие массива. Основные правила работы с массивами в Си
- •1.5.2. Примеры программ с массивами.
- •1.5.3. Инициализация массивов
- •1.5.4. Указатели в Си10
- •1.5.5. Связь массивов с указателями в Си
- •Часть. Функции и многофайловые программы в Си
- •2.1. Общие сведения о подпрограммах и функциях
- •2.2. Функции си
- •2.2.1. Описание функции
- •2.2.2. Обращение к функции
- •2.2.3. Место описания функции в программе
- •2.2.4. Примеры программ, использующих функции
- •2.3. Краткие сведения о препроцессоре Си
- •2.3.2.Директива макроопределения #define
- •2.3.3. Директива #include включения файлов
- •2.3.4. Директивы условной компиляции
- •2.415. Многофайловые си-программы
- •2.4.1. Структура программы на Си. Область действия переменных
- •2.4.2. Время жизни и класс памяти переменных
- •Описатели класса памяти
- •2.4.3 Понятие о файле проекта
- •Часть. Обработка символьной информации и документов сложной структуры
- •3.1. Обработка символьной информации на Си
- •3.1.1. Символьный тип
- •3.1.2. Работа со строками символов в Си. Строковые литералы. .
- •3.1.3. Функции и макросы для работы с символьной информацией
- •3.1.4. Примеры программ
- •3.2. Тип "структура" в Си
- •Структура
- •3.3. Файлы в Си
- •3.3.1. Общие понятия.
- •3.2.Функции Си для работы с файлами
- •3.3.3. Примеры программ, использующих файлы
- •Литература
- •Содержание
1.5.2. Примеры программ с массивами.
Пример 1. Дан массиваиз 20 элементов. Вычислить сумму положительных и количество неположительных элементов массива.
Исходные данные.а– заданный массив
Выходные данные.s - сумма положительных элементов массива, k – количество неположительных элементов.
Промежуточные переменные. i – счетчик элементов массива.
Алгоритм состоит из ввода исходных данных, цикла, в котором накапливаются s иk(цикл управляется переменнойi,которая изменяется от 0 до 19) и вывода результатов. Перед циклом накапливаемым переменным присваиваются начальные значения. Основной частью тела цикла является ветвление. Блок-схема алгоритма приведена на рис. 9. Далее приведена Си-программа.
#include <stdio.h>
#include <math.h>
void main()
{float a[20],s; int k,i;
printf("Введите массив из 20 элементов\n");
/* Далее цикл для поэлементного ввода массива*/
for (i=0; i<20; i++)
scanf("%f", &a[i]);/*Далее алгоритм по блок-схеме*/
s=0; k=0;
for (i=0; i<20; i++)
if (a[i]>0)
s=s+a[i];
else
k=k+1;
printf(" s=%f k=%d",s,k );
}
1.5.3. Инициализация массивов
При описании элементы массивов можно инициализировать, т. е. задавать им начальные значения. Эти значения записываются в фигурных скобках через запятую и присваиваются элементам массива последовательно в порядке их нумерации. Значений не может быть больше, чем объявлено элементов массива. Если значений меньше, чем элементов в массиве, то оставшиеся элементы считаются неинициализированными9.
Список инициализирующих значений можно использовать для определения размера массива по первому индексу. Поясним это на примерах.
Одномерные массивы
Пусть число элементов массива задано явно. Например,
сhar a[10]={'A', 'B', 'C', 'D'};
в результате a[0] имеет значение'A', a[1] - 'B', a[2] - 'C', a[3] - 'D',остальные элементы массива не инициализированы.
Пусть число элементов массива явно не задано:
сhar a[]={'A', 'B', 'C', 'D'};
С помощью такой инструкции описан и инициализирован массив из четырех элементов.
Двумерные массивы
Присваивание перечисленных значений происходит по строкам (в соответствии с расположением массивов в памяти компьютера).
Пример: int m[2][3]={0,1,2,5,6,7};
Эта инструкция объявляет и присваивает начальные значения матрице .Можно не указывать число строк, тогда оно будет определено по числу начальных значений, т. е. инструкция
int m[ ][3]={0,1,2,5,6,7};приведет к такому же результату.
Значения, соответствующие одной строке, могут быть заключены во внутренние фигурные скобки; это может быть полезно, если стороки инициализируются не полностью. Так, инструкция
int m[ ][3]={{0},{1,2}}; объявляет матрицуm размером 2*3 и частично инициализирует ее.
, незаполненные элементы не инициализированы: неопределены, еслиm - локальная переменная, и равны нулю, если глобальная.
Таким образом, при объявлении массива количество его элементов должно быть задано или явным указанием в квадратных скобках или количеством значений при инициализации. Исключение из этого правила составляют массивы-аргументы функций (см. п.2.2.1).
1.5.4. Указатели в Си10
Указатель- это специальная переменная, которая содержит адрес другой переменной.
Работа с указателями и динамической памятью обычно относится к области системного программирования. В Си указатели активно используются даже в простых инструкциях языка. По-видимому, это является следствием того, что Си разрабатывался как язык системного программирования. В п.1.3.3 уже показано использование указателей в функции ввода scanf().В следующем параграфе мы рассмотрим применение указателей для работы с массивами. Этот параграф предваряет его и посвящен правилам работы с указателями в Си.
Основные операции для работы с указателями (см., также таблицу 3): * - взятие содержимого по адресу (*i- содержимое переменной с адресомi) &- взятие адреса (&a- адрес переменной а).
При описании указателя задается тип значения, на которое он указывает. Описание имеет вид:
тип *имя_указателя;
Можно интерпретировать смысл этой конструкции так:: объявляется переменная, содержимое которой имеет данный тип.
Пример: int *i, j, *pointj;
j -переменная целого типа;i, pointj - указатели на значения целого типа.
При описании указателей возможна их инициализация. Пример:
int v1, *pointv1=&v1, *p=(int*)200;
Здесь указателю pointv1 задается начальное значение, равное адресу переменнойv1,а указателю р - значение константы 200, приведенное к типуint*, т. е. адрес двухсотой от начала рассматриваемой области памяти ячейки типаint.
Как данные любого типа, указатели могут быть переменными или константами. Указателями-константами, например, являются адреса переменных, имена массивов, явные константы (например, (int*)200), а также константаNULL (нулевой или несуществующий адрес).
При работе с указателями-константами надо помнить следующее:
нельзя брать содержимое от константы без приведения типа; запись *200 является некорректной в отличие от *(int*)200
нельзя брать адрес константы (например, некорректна запись &200), в Си адрес константы считается недоступным;
нельзя определять адрес выражения.
Размер памяти, отводимой под указатель, зависит от модели памяти. Для "малых" моделей памяти (tiny, small) адресация осуществляется в пределах одного сегмента памяти, и указатель занимает два байта, для "больших" моделей памяти (large, huge) указатели занимают четыре байта.
Кроме операции *, к указателям применимы операции сравнения (<, <=, >, >=, ==, !=), присваивания, арифметические операции сложения, вычитания, инкремента и декремента. Справа от операции присваивания должен стоять указатель того же типа, что и слева (от операции присваивания),или указатель NULL. Сравнивать можно указатели одного типа (или указатель произвольного типа сNULL).
Нельзя суммировать (вычитать) указатели, можно только прибавлять к ним (вычитать из них) целую величину. При этом результат операции зависит не только от значения операндов, но и от типа, с которым связан указатель. Если объявление указателя р имеет вид тип *р,то в результате операторар=р+k, гдеk- некоторое целое значение, р увеличится наk*sizeof (тип).
Пример. int *p; long int pp;... p++; /*p увеличилось на 2*/
pp++; /*pp увеличилось на4*/