ТОП 10:

Программирование циклических процессов



С использованием одномерных массивов и строк

 

Цель работы:

Изучить правила работы с одномерными массивами, а также особенности работы со строковы­ми объектами как одномерными символьными массивами.

 

Краткие теоретические сведения

Массив – конечномерная последовательность данных одного типа. Массив – объект сложного типа. Каждый элемент массива определяется именем массива и индексом (целое число), по которому к элементу массива производится доступ. Рассмотрим одномерные массивы. Индексы массивов в языке С начинаются с 0. В программе одномерный массив объявляется следующим образом:

<Тип> <имя массива>[размер];

где размер – количество элементов одномерного массива.

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

Пример объявления массива целого типа:

int a[5];

в массиве а первый элемент а[0], второй – а[1], …, пятый - а[4]. В языке С не проверяется выход индекса за пределы массива. Корректность использования индексов элементов массива должен контролировать программист.

Пример работы с одномерным массивом

В массиве целых чисел найти индекс и значение максимального эле­мента и переставить его с первым элементом. Программа также дол­ж­на подсчитать количество положительных и отрицательных элементов данного массива.

Текст программы может быть следующим:

 

#include <stdio.h>

#include <conio.h>

void main(void)

{ // Объявление с инициализацией,

int a[4]={-1,-20,4,100}; // индексы принимают значения от 0 до 3

int i,index,max,kp=0,ko=0,zam,n=4;

clrscr();

puts("\n Исходный массив ");

for (i=0; i<n; i++)

printf("%d ",a[i]); // Вывод элементов исходного массива

max=a[0];

for (i=1; i<n; i++)

{

if (a[i]>max)

{

max=a[i]; index=i; }

}

zam=a[0];a[0]=a[index];a[index]=zam;

for (i=0;i<n;i++)

{

if (a[i]<0) ko++;

else kp++;

}

puts("\n Результаты работы программы ");

for (i=0; i<n; i++)

printf("%d ",a[i]); // Вывод элементов массива

printf("\n положительных элементов: %d \n",kp);

printf("\n отрицательных элементов: %d \n\n Press any key...",ko);

getch();

}

Строки как одномерные массивы символов

Работа со строками в языке С реализована путем использования одномерных мас­сивов типа char, т.е. строка символов – это одномерный массив типа char, заканчиваю­щийся нулевым байтом. Нулевой байт – это байт, каждый бит которого равен нулю, при этом для нулевого байта определена символьная константа ´\0´ (признак окончания строки или нуль-терминатор). Поэтому, если строка должна состоять из k символов, то в описании массива необходимо указать размер k+1.

Например, описание char a[7], означает, что строка содержит шесть символов, а последний байт отведен под нуль-терминатор.

Строковая константа в языке С – это набор символов, заключенных в двойные кавычки. Например: “Лабораторная работа по строкам”. В конце строковой константы явно указывать символ ´\0´ не нужно, так как это сделает компилятор языка С.

Строки можно инициализировать при декларировании, например:

char S1[10]=”123456789”, S2[ ]=”12345”;

в последнем случае размер строки будет установлен по фактическому количеству символов.

Для ввода строки с клавиатуры дисплея используются две стандартные библи­отечные функции, прототипы которых приведены в файле stdio.h.

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

Библиотечная функция gets( ) обеспечивает ввод строки с пробелами внутри этой строки. При этом ввод строки символов завершается нажатием клавиши ENTER.

Обе функции автоматически ставят в конец строки нулевой байт. И, кроме того, так как строка – это символьный массив, а имя массива – это указатель на его начало в памяти, то символ «&» перед именами строк при использовании этих функций указывать не надо.

Вывод строк выполняют функции printf( ) или puts( ). Обе функции выводят символьный массив до первого нулевого байта. Функция printf( ) не переводит курсор после вывода на начало новой строки, программист должен предусмотреть такой перевод в строке формата. Функция puts( ) автоматически переводит курсор после вывода строковой информации в начало новой строки.

Операции над строками как объектами сложного типа, рекомендуется выполнять, используя стандартные функции. Декларации функций для работы со строками размещены в файле string.h. Рассмотрим наиболее часто используемые:

1. Функция strcpy(S1, S2) - копирует содержимое строки S2 в строку S1.

2. Функция strcat(S1, S2) - присоединяет строку S2 к строке S1 и помещает ее в массив, где находилась строка S1, при этом строка S2 не изменяется. Нулевой байт, который завершал строку S1, заменяется первым символом строки S2.

3. Функция strcmp(S1, S2) сравнивает строки S1 и S2 и возвращает значение =0, если строки равны, т.е. содержат одно и то же число одинаковых символов; значение <0, если S1<S2; значение >0, если S1>S2.

4. Функция strlen(S) возвращает длину строки, т.е. количество символов, начиная с первого (S[0]) и до нуль-терминатора, который не учитывается.

5. Функции преобразования строки S в число:

- целое: int atoi(S);

- длинное целое: long atol(S);

- действительное: double atof(S);

при ошибке данные функции возвращают значение 0.

6. Функции преобразования числа V в строку S:

- целое: itoa(int V,char S,int kod);

- длинное целое: ltoa(long V,char S,int kod); 2<=kod<=36, для отрицательных чисел kod=10.

Операция sizeof

Для определения размера памяти, необходимого для размещения объектов в языке С, используется унарная операция sizeof(параметр), параметр – тип объекта или его идентификатор (только не имя функции). Операция sizeof вычисляет размер памяти в байтах, отводимый под объект. Если указан идентификатор сложного объекта (массив, структура, объединение), то результатом является размер всего сложного объекта. Например:

sizeof(int) результат 2 байта;

int b[5]; sizeof(b) результат 10 байт;

int c[3][4]; sizeof(c) результат 24 байта.

Указатели и операции над адресами

Обращение к объектам любого типа в языке C может проводиться по имени, как мы до сих пор делали, и по указателю (косвенная адресация).

Указатель – это переменная, которая может содержать адрес некоторого объекта в памяти компьютера, например, адрес другой переменной. И через указатель, установленный на переменную, можно обращаться к участку оперативной памяти, отведенной компилято­ром под ее значения.

Указатель объявляется следующим образом:

<тип> *<идентификатор>;

Например:

int *a, *d;

float *f;

Здесь объявлены указатели a, d, которые можно инициализировать адресами целочисленных переменных, и указатель f, который можно инициализировать адресами вещественных переменных.

С указателями связаны две унарные операции: & и *. Операция & означает «взять адрес». Данная операция допустима только над переменными. Операция * - «значение, расположенное по указанному адресу» и работает следующим образом:

- определяется местоположение в оперативной памяти переменной типа указатель;

- извлекается информация из этого участка памяти и трактуется как адрес переменной с типом в объявлении указателя;

- производится обращение к участку памяти по выделенному адресу для проведения некоторых действий.


Пример:

int x, // переменная типа int

*y; // указатель на элемент данных типа int

y=&x; // y - адрес переменной x

*y=1; // по адресу y записать 1, в результате x = 1

 

Связь указателей и массивов

Указатели и массивы в языке С тесно связаны между собой. Имя массива является указателем на его первый элемент, т.е. для массива int v[10] v и v[0] имеют одинаковые значения, т.к. адрес первого (с индексом 0) элемента массива - это адрес начала последовательно расположенных элементов массива. Рассмотрим обращение к элементам массива на примере. Пусть объявлены - массив из 100 объектов типа float и указатель на объект типа float:

float p[100];

float *q;

int i;

если выполнить операцию q=p; то обращения к элементу массива p: p[i] , *(q+i) и *(p+i) эквивалентны.

Таким образом, для любых указателей можно использовать две эквивалентные формы выражений для доступа к элементам массива: q[i] и *(q+i). Первая форма удобнее для читаемости текста, но вторая обычно эффективнее по быстродействию программы.

Очевидна эквивалентность выражений

&q[0] <-> &(*q) <-> q

*q <-> q[0]

 

Пример 1: Упорядочить по алфавиту массив строк (не более 20) длиной не более 10 символов в каждой.

 

#include<conio.h>

#include<stdio.h>

#include<string.h>

void main()

{

char s[20][10],r[10];

int i,j,n;

clrscr();

puts(" Введите количество слов ";

scanf(“%d”,&n);

for(i=0;i<n;i++)

scanf("%s",&s[i]);

for(i=0;i<(n-1);i++)

for(j=(i+1);j<n;j++)

if(strcmp(s[i],s[j])>0)

{

strcpy(r,s[i]);

strcpy(s[i],s[j]);

strcpy(s[j],r);

}

for(i=0;i<n;i++)

printf("\n %s",s[i]);

getch();

}

 

Пример 2: Проверить, является ли введенная строка (не более 80 символов) палиндромом (справа налево читается так же, как и слева направо).

#include <stdio.h>

#include <string.h>

#include <conio.h>

 

void main(void)

{

char s[80],s1[80];

int i, k;

clrscr();

puts(" Введите исходную строку (не более 80 символов) ");

gets(s);

k=strlen(s);

puts(" Результаты работы программы ");

for (i=0; i<k; i++)

printf("%c",s1[i]=s[k-i-1]); // Переворачиваем строку s

s1[k]=’\0’; // Устанавливаем конец строки

printf(“ %s\n”,strcpy(s1,s) ? ” YES - Pаlindrom!”:” NO !”)

printf("\n Press any key...");

getch();

}

 

Массивы указателей

В языке С можно использовать массивы указателей, элементы которых содержат, как правило, указатели на строковые данные. Объявляется такой массив, например, так char *m[5]. Здесь массив m[5] – массив, который может содержать пять адресов данных типа char.

Массив указателей можно при объявлении инициализировать, т.е. назначать его элементам конкретные адреса. С помощью массивов указателей типа char* удобно получать доступ к строкам в виде массивов символов.

В качестве примера приведена программа, формирующая массив указателей с одновременной инициализацией его элементов. Программа выводит на экран номер строки, ее адрес и значение.

 

#include <stdio.h>

#include <conio.h>

 

void main(void)

{

int i,k;

char *m[]={

"Winter",

"Spring",

"Summer",

"Automn"};

k=sizeof(m)/sizeof(*m);

printf("\n Количество строк = %d",k);

for(i=0; i<k; i++)

printf("\n Номер - %d; Адрес - %p; Строка: %s", i+1, m[i], m[i]);

getch();

}

В результате получим:

Количество строк = 4

Номер - 1; Адрес - 0042007C; Строка: Winter

Номер - 2; Адрес - 00420074; Строка: Spring

Номер - 3; Адрес - 0042006C; Строка: Summer

Номер - 4; Адрес - 00420064; Строка: Automn

 

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

Замечание.Функция printf() и спецификатор преобразования %S допускают использование в качестве параметра указатель на строку, однако при этом выводится не значение указателя m[i], а содержимое адресуемой им строки, в то время как спецификатор %P выводит значение указателя m[i].

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

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

 

#include <stdio.h>

#define b 6

void main ()

{ float array [ ]={5.0,2.0,3.0,1.0,6.0,4.0};

float *pmin[b], *pmax[b], *e;

int i,j;

for (i=0;i<b;i++)

pmin[i]=pmax[i]=&array[i];

for(i=0;i<b-1;i++)

for(j=i+1;j<b;j++)

{

if(*pmin[i]<*pmin[j])

{ e=pmin[i];

pmin[i]=pmin[j];

pmin[j]=e;}

if(*pmax[i]>*pmax[j])

{ e=pmax[i];

pmax[i]=pmax[j];

pmax[j]=e;}

}

printf(’’ \n По убыванию: \n”);

for(i=0;i<b;i++)

printf(“\t %5.3f”,*pmin[i]);

printf(“\n По возрастанию: \n”);

for(i=0;i<b;i++)

printf(“\t%5.3f”,*pmax[i]);

}

 

Варианты индивидуальных заданий

1. Ввести целое число N. Выделить из этого числа цифры, кратные 3, и записать их в одномерный массив.

2. Для заданного целого числа N определить цифру а, наиболее часто встречающуюся в числе. Сформировать одномерный массив из 5 элементов: a, а2, а3, а4, а5.

3. Элементы заданного массива X циклически сдвинуть на K позиций вправо (влево).

4. Дано число N целого типа. Определить, симметрично ли оно, т.е. одинаковы ли цифры слева и справа (12321). Записать 3 последние цифры в одномерный массив.

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

6. Даны координаты n точек на плоскости: x1,y1, x2,y2,…. xn,yn . Найти номера двух точек, расстояние между которыми наибольшее.

7. Заданы два массива по N целых чисел. Найти наименьшее среди чисел первого массива, которое не входит во второй массив.

8. Дан массив из N целых чисел. Определить количество инверсий в этом массиве (т.е. таких пар элементов, в которых большее число находится слева от меньшего: xi > xj при i < j).

9. Ввести строку символов. Определить длину введенной строки L, и если длина L четная, то удаляются 2 первых и 2 последних символа.

10. Ввести строку символов. Определить длину введенной строки L, и если длина L нечетная, то удаляется символ, стоящий посередине строки.

11. Ввести строку символов. Заменить в ней каждый второй символ ! на $.

12. Ввести строку символов. Заменить в ней пробелы на символ $.

13. Ввести строку символов. Определить длину введенной строки L, и если длина L>10, то удалить все цифры.

14. Ввести строку символов. Определить длину введенной строки L, и если длина L кратна 3, то удаляются все числа, делящиеся на 3.

15. Ввести строку символов. Определить длину введенной строки L, и если длина L кратна 5, то подсчитывается количество скобок всех видов.

16. Ввести строку символов. Определить длину введенной строки L, и если длина L кратна 4, то первая часть строки меняется местами со второй.

17. Ввести строку символов. Определить длину введенной строки L, и если длина L=10, то удаляются все буквы - A... Z.

18. Ввести строку символов. Определить длину введенной строки L, и если длина L >15, то удаляются все буквы - a…z.

19. В строке символов поменять местами символы на четных и нечетных позициях.

20. Ввести строку символов. Определить длину введенной строки L, и если длина L>6, то выделяется подстрока в { } скобках.

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

 

1. Укажите типы массивов, применяемых в языке С.

2. Формы (способы) работы с элементами массива.

3. Как описываются строки в языке С?

4. Чем отличаются функции scanf() и gets(), printf() и puts()?

ЛАБОРАТОРНАЯ РАБОТА № 4







Последнее изменение этой страницы: 2016-04-08; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.207.106.142 (0.02 с.)