Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПЯВУ - методичка1.doc
Скачиваний:
8
Добавлен:
08.11.2019
Размер:
683.52 Кб
Скачать

Занесение данных в массив

Исходные данные в элементы массива можно занести тремя способами:

  1. Инициализацией массива.

  2. Функцией ввода.

  3. Присваиванием значений.

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

Одномерный массив можно инициировать полностью:

int ar [5]={1,2,3,4,5} или частично: int ar[5]={4,5};

тогда ar[0]=4, ar[1]=5, остальные элементы равны 0, поэтому легко выполнить обнуление массива: int ar[5]={0}.

Двумерный массив можно инициировать одним списком:

int ar [2][3]={1,2,3, 4,5,6}; либо отдельными списками построчно:

int ar [2][3]={{1,2,3},{4,5,6}}; либо неполными списками:

int ar [2][3]={{1,2},{4}}; что соответствует списку {{1,2,0},{4,0,0}}.

Ввод данных в массив функцией scanf ( ) выполняется поэлементно, для чего используется оператор цикла. Например, ввод одномерного массива:

for (i=0; i<5; i++) scanf (“%d”,&ar[i]); или scanf (“%d”, ar+i) c адресным выражением.

Присваивание значений элементам массива выполняется при вычислении выражений, определяющих элементы массива, например,

for (i=0; i<5; i++) a[i]=sin(i+1)+cos(2*i+1).

Многомерные массивы

Рассмотрим более подробно работу с многомерными массивами. Размерность массива – это число индексов, используемых для ссылки на конкретный элемент в массиве. Многомерный массив – это массив, состоящий из массивов, то есть его элементами являются массивы. Например, двухмерный массив, описанный как int m[2][3], состоит из двух элементов-строк (одномерных массивов): m = { m[0], m[1] } по три элемента в каждом:

массив с индексом 0: m[0] с элементами m[0][0], m[0][1], m[0][2],

массив с индексом 1: m[1] с элементами m[1][0], m[1][1], m[1][2].

Имя массива m является указателем-константой на начало двухмерного массива: m= &m[0][0]; в свою очередь элементы m[0], m[1] являются указателями-константами на начала своих одномерных массивов: m[0] = &m[0][0], m[1] = &m[1][0]. Поскольку m = m[0] = &m[0][0], постольку имя массива m является указателем на массив указателей на начала своих одномерных массивов, что определяет вид адресных выражений для двухмерного массива. Для ссылки на элементы двухмерного массива “точкой отсчета” может быть как самый первый элемент, так и указатели на строки массива.

Адрес начала i-й строки массива (m[i]) можно получить выражением *(m+i), где имя массива m используется как адрес начала массива указателей. Адрес j-го элемента i-й строки определяется эквивалентными выражениями:

m[i] + j = *(m+i) + j = &m[i][j].

Поэлементный ввод-вывод двумерного массива можно осуществить несколькими способами, используя индексные и адресные выражения.

Пример. Ввести и вывести по строкам двумерный массив.

Программа:

void main ()

{ int m[2][3], i, j; /* описание массива и параметров циклов */

puts (“Ввод массива m по строкам”);

for (i=0; i<2; i++) /* цикл по строкам */

for (j=0,j<4,j++) /* цикл по столбцам */

scanf (“%d”, &m[i][j]); /* ввод элемента массива */

/* варианты адресных выражений: m[i]+j; *(m+i)+j) */

puts (“Вывод массива m по строкам:”);

for (i=0; i<2; i++) /* цикл по строкам */

{ for (j=0; j<4; j++) /* цикл по столбцам */

printf (“%d”, m[i][j]); /* индексное выражение */

printf (“\n”); /* переход на новую строку */

/* варианты адресных выражений: *(m[i]+j); *(*(m+i)+j) */

}

}

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

Пример. Найти индекс и значение минимального элемента массива.

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

Программа:

# define k 10 /* количество элементов массива */

void main ( )

{ float a[k]; int i; im; /* описание массива и переменных */

clrscr(); /* очистка экрана */

puts (“Ввести %d элементов массива”; k);

for (i=0;i<k;i++) /* цикл по индексам элементов */

scanf (“%f”, ar+i); /* ввод элемента */

im=0; /* индекс начального элемента */

for (i=1; i<k; i++) /* цикл поиска индекса минимума */

if (a[i] < a[im]) im=i; /* проверка элемента на минимум */

printf (“Минимум = %f индекс=%d”, a[im], im);

}

Пример. Упорядочить по возрастанию элементы массива методом простого выбора.

Программа:

#define k 10

void main ( )

{ float a[k], r; /* описание массива и переменной */

int i, j, im; /* описание переменных индексов */

clrscr(); /* очистка экрана */

printf ( “Ввод массива :\n”);

for (i=0; i<k; i++) scanf (“%f”, a+i); /* цикл ввода элементов массива */

for (j=0; j<k; j++) /* цикл шагов упорядочения */

{ im=j; /* начальный индекс */

for ( i=j+1; i<k; i++) /* цикл поиска индекса */

if ( a[i]<a[im] ) im=i; /* минимального элемента */

if ( im != j ) /* если индекс изменился */

{ r=a[j]; /* перестановка минимального */

a[j]=a[im]; /* элемента в начало неупоря- */

a[im]=r; /* доченной последовательности */

} /* конец цикла поиска */

} /* конец цикла упорядочения */

puts (“Массив упорядочен по возрастанию”);

for ( i=0; i<k; i++ ) printf (“%5.2f”, a[i] ); /* цикл вывода массива */

} /* конец программы */

Символьные массивы

Описание массива типа

char string[80]; позволяет описывать и обрабатывать символьные данные, однако тип char[ ] относится к целому типу, поскольку имеет дело с ASCII-кодами символов.

Особым случаем массива является строковый литерал (строка-константа) – последовательность любых символов, заключенных в кавычки: “это строковый литерал”. Строковый литерал представляется в памяти как массив элементов типа char[ ], в конце которого помещен символ ‘\0’ (нулевой байт); его называют ACSIIZ-строкой. Как и с любым массивом, со строковым литералом связан указатель-константа на первый элемент строки.

Можно также описать указатель символьного типа

char *str; который пока не связан ни с какой символьной информацией.

Символьные массивы можно инициировать, вводить и выводить поэлементно, как и числовые массивы, однако более рационально выполнять инициирование с помощью строковых литералов, а ввод-вывод по ссылке на имя символьного массива, которое является указателем-константой на первый элемент массива (с индексом 0).

Совершенно идентичны следующие описания с инициализацией:

char string [10] = {‘с’,’л’,’о’,’в’,’о’,’\0’};

char string [10] = ”слово”;

Последнее описание выглядит проще, а нулевой байт записывается в конце строки автоматически. Адрес первого элемента (‘с’) становится синонимом имени массива string. Строка в массиве ограничена нулевым байтом, а остальные элементы массива не используются. Можно не задавать размер массива, компилятор выделит нужное число элементов плюс нулевой байт при инициализации:

char string[ ]=”слово”;

Описание вида char * str; выделит место в памяти только для указателя str, а место для отсутствующей строки не выделяется. Можно инициировать указатель строковым литератором, например,

char * str = “Иванов А.С.”; или присваиванием определить указатель:

str = “Иванов А.С.”; тогда указатель получит адрес первого символа литерала, который располагается в сегменте данных программы.

Стандартные функции ввода-вывода можно использовать для обработки символьных данных.

Пример. Ввести и вывести строку символов.

Программа.

void main ( )

{ char name [25];

puts (“Введите Фамилию И.О.:”);

gets ( name );

puts (“Вывести Фамилию И.О.:”);

puts ( name ); /* или printf(“%s”, name); */

}

Функция scanf (“%s”, name) менее удобна, поскольку вводит символы до первого пробела.

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

#include <alloc.h> .

Пусть дано описание указателя

char * str; тогда оператор вида

str = (char*) malloc (30); выделит 30 байт в динамической памяти и запишет адрес начала этого блока в указатель str.

Можно также использовать другую функцию:

str = (char*) calloc (количество, размер элемента); которая возвращает указатель (адрес) на выделенный блок памяти = количество * размер элемента (байт) и обнуляет выделенную память.

После использования блока динамической памяти его надо освободить функцией

free (указатель), например, free (str).

Пример. Ввод и вывод строк в динамической памяти.

Программа:

#include <alloc.h>

void main ( )

{ char * pname;

pname = (char*) malloc (30); /* выделение динамической памяти */

printf (“Введите Фамилию И.О.:”);

gets ( name );

printf (“Вывод Фамилии И.О.:”);

free (name ); /* освобождение динамической памяти */

}

Особый случай – инициализация двухмерного массива строковыми литералами. Многомерные массивы могут инициироваться и без указания одной (самой левой) из размерностей массива в [ ]. Компилятор сам определяет число элементов по числу членов в списке инициализации.

Например,

char str [ ] [80] = { “Первая строка”,

“Вторая строка”,

“Третья строка” };

Как было показано выше, элементы массива str[0], str[1], str[2] являются указателями на строки двухмерного массива, что можно использовать при обработке таких массивов.

Пример. Ввод и вывод строковых данных.

Программа:

void main ( )

{ int i ;

char buffer [3][80];

puts (“Введите строки в буфер:”);

for (i=0; i<3; i++) gets (buffer[i]);

puts (“Вывод строк из буфера:”);

for (i=0; i<3; i++) puts (buffer[i]);

}

Пример. Скопировать символы из массива s1, на который ссылается указатель ps1, в массив s2, на который ссылается указатель ps2. Исходная строка заканчивается символом ‘\0’.

Программа:

void main ( )

{ char s1[80], s2[80], *ps1=s1, *ps2=s2; /* инициализация указателей */

clrscr (); /* очистка экрана */

puts (“Введите строку и нажмите Enter:”);

gets (s1); /* чтение строки и запись нуль-байта */

while (*ps1!= ’\0’) /* цикл пока не конец строки */

{ *ps2 = *ps1; /* копирование символа */

ps1++; /* переход к следующему символу в s1 */

ps2++; /* переход к следующему символу в s2 */

}

*ps2 = ’\0’; /* запись нуль-байта в строку s2 */

printf (“Скопирована строка :\n%s”,s2); /* вывод строки s2 */

} /* конец программы */

С учетом старшинства и действий операций присваивания (=), разадресации (*) и увеличения (++) копирование символов можно выполнить одним оператором while () с пустым телом цикла с одновременной проверкой условия:

while ( *ps2++ = *ps1++ ) ;

Язык Си (и Си++) одновременно и любят и не любят за возможность использования столь лаконичных конструкций, которые требуют высокой квалификации программистов, но затрудняют понимание алгоритма.

Проще выглядит копирование символов с помощью оператора цикла:

for ( i=0; s2[i]=s1[i]; i++ ) ; /* тело цикла – пустой оператор */