Способы объявления и обращения к элементам массивов
Способы объявления и обращения
К элементам одномерных массивов
Объявление одномерного массива с явным указанием количества элементов массива:
<тип_элементов_массива> <имя_массива> [<количество_элементов>];
Обращение к элементам одномерного массива в общем случае можно представить индексированием:
<имя_массива> [<выражение>];
где <имя_массива> – указатель–константа, адрес нулевого элемента массива; <выражение> определяет индекс элемента массива.
Элементы одномерного массива располагаются в ОП последовательно друг за другом: нулевой, первый и т.д. При объявления массива
int а[10];
компилятор выделяет массиву ОП для размещения его элементов в размере sizeof(<тип_элементов_массива>)*<размер_массива> байт, т.е. 4 ∙ 10 = 40 байт. Запись &a[i] равносильна записи (а + i). В программе &a[i] или (а + i) определяет адрес i-го элемента массива. На машинном уровне (в соответствии с определением операций над указателями) адрес i-го элемента массива &a[i] формируется в виде а + i*sizeof(int) .
В связи с вышеизложенным, будут справедливы соотношения:
&а а + 0 &а[0] – адрес нулевого элемента массива а;
а + 2 &а[2] – адрес второго элемента массива а;
а + i &a[i] – адрес i-го элемента массива а;
*а *(а + 0) *(&а[0]) а[0] – значение нулевого
элемента массива а;
*(а+2) а[2] – значение второго элемента массива;
*(а + i) a[i] – значение i-го элемента массива;
|
|
*а + 2 а[0] + 2 – сумма значений а[0] и 2.
Если р – указатель на тип данных, совпадающий с типом элементов массива а и адрес, который содержит указатель р, совпадает с адресом массива а, то а и р взаимозаменяемы. При этом
р &а[0] а + 0;
р + 2 &а[2] а + 2;
*(р + 2) *(&а[2]) а[2];
*(p + i) *(&a[i]) a[i].
Способы объявления и обращения
К элементам двухмерных массивов
Рассмотрим объявление и связь указателей и элементов двухмерных массивов. Двухмерный массив в языке С++ рассматривается как совокупность одномерных массивов (его строк), а строка – совокупность элементов одномерного массива.
Объявление двухмерного массива с явным указанием количества элементов массива:
<тип_элементов_массива> <имя_массива>[<кол–во_строк>][<кол–во_столбцов>];
Для обращения к элементам двухмерного массива используется два индекса (индексных выражений):
<имя_массива>[<выражение1>][<выражение2>];
Индексные выражения вычисляются слева направо, полученные значения применяется после вычисления последнего индексного выражения. Элементы массивов располагаются в ОП таким образом, что быстрее изменяются самые правые индексы, т.е. элементы одномерного массива располагаются подряд, а двухмерного – по строкам.
|
|
Пример объявления двухмерного массива значений типа:
int a[m][n];
Этот массив состоит из m одномерных массивов (строк), каждый из которых содержит n элементов (столбцов). При работе с этим двухмерным массивом можно использовать одно или два индекса (индексных выражения), например, а[i][j] содержит 2 индекса. Такая запись используется для обращения к элементу, расположенному на пересечении i-й строки и j-го столбца массива. Для получения значения этого элемента вначале вычисляются индексные выражения, затем определяется адрес элемента массива в ОП и извлекается его значение.
a[i] содержит один индекс: подобная запись определяет адрес одномерного массива, т.е адрес начала i-й строки массива.
Имя массива а не содержит индекса и определяет адрес массива, т.е. адрес его нулевого элемента.
Таким образом, обращение к двухмерным массивам с помощью имени и только одного индекса определяет указатель на начало соответствующей строки массива (адрес ее нулевого элемента). Напомним, что в одномерном массиве адрес i-го элемента массива &a[i] формируется в виде а + i*sizeof(int). Используя это, определим соотношения:
a[0] &а[0][0] a + 0*n*sizeof(int);
|
|
a[1] &а[1][0] а + 1*n*sizeof(int);
a[i] &а[i][0] а + i*n*sizeof(int);
Обращение к элементам многомерного массива более детально рассмотрим на примере двухмерного массива:
int a[3][4]; //а – указатель-константа
int *р=&а[0][0]; // р – указатель-переменная
После этого указатель р можно использовать вместо указателя а для обращения к строкам или элементам массива. В ОП элементы массива а располагаются таким образом, что быстрее всех изменяется самый правый индекс, т.е. в последовательности: a[0][0] а[0][1] а[0][2] а[0][3] а[1][0] ... а[2][0] а[2][1] а[2][2] а[2][3]
При этом для обращения к массиву а можно использовать имена:
&а а &а[0][0] *а – адрес элемента 0-й строки и 0-го столбца массива а;
*(&а[0][0]) а[0][0] – значение элемента 0-й строки 0-го столбца массива а;
a[i] (а+i) *(а+i) &a[i][0] – адрес начала i-й строки, т.е. адрес элемента i-й строки и 0-го столбца;
*a[i] *(&a[i][0]) a[i][0] – значение 0-го элемента i-й строки;
a[i][j] *(*(a+i)+j) *(a[i]+j) a[i][j] – значение элемента i-й строки j-го столбца массива а;
где (а+i) *(a+i) a[i] – адрес 0-го элемента i-й строки, т.е. &a[i][0];
(*(a+i)+j) – адрес j-го элемента i-й строки, т.е. &a[i][j];
*(*(a+i)+j) – значение j-го элемента i-й строки, т.е. a[i][j].
Значение адреса начала i-й строки (адреса 0-го элемента i-й строки) на машинном уровне формируется в виде:
|
|
a[i] а+i (a+i*n*sizeof(int))
где n — количество элементов в одной строке. Таким образом, адрес (i+1)-й строки смещен относительно i-й строки на (n*sizeof(int)) байт, т.е. на одну строку массива. Выражение a[i][j] компилятор С++ переводит в эквивалентное выражение *(*(а+i)+j).
К элементам двухмерного массива можно обратиться и с помощью скалярного указателя на массив.
Например, после объявления:
int a[m][n], *р = &а[0][0];
*(р+i*n+j) // значение j-го элемента в i-й строке;
где n – количество элементов в строке; i*n+j – смещение элемента a[i][j] относительно начала массива а.
Пример 1. Дан одномерный динамический массив. Вычислить среднее арифметическое модулей элементов массива.
Ход выполнения работы
1. Алгоритмы решения задач с использованием динамических массивов схожи с алгоритмами, использующими статические массивы.
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление вещ: *а, sum ; цел: i, n // ввод количества элементов массива ввод n выделить динамическую память под указатель a // ввод элементов массива для i=0 до n-1 шаг 1 ввод ai все для i //сначала сумма элементов равна нулю sum=0 для i=0 до n-1 шаг 1 // в цикле изменяется номер i // элемента массива // нужный элемент добавляется к // сумме sum=sum+ai все_для i // находим среднее арифметическое sum=sum/n // печатаем полученное значение печать sum // вывод массива на экран для i=0 до n-1 шаг 1 вывод ai все_для i освободить выделенную под указатель a динамическую память | #include "stdio.h" #include "stdlib.h" int main ( ) { float *а, sum; int i, n; // ввод n printf ("n=" ); scanf ("%i", &n); a=(float*)malloc(n*sizeof(float)); //ввод одномерного динамического //массива с клавиатуры for ( i=0; i<=n-1; i++ ) { printf(“a%i=”,i); scanf(“%f”,a+i); } // сначала сумма элементов равна нулю sum=0; // вычисление суммы элементов for ( i=0; i<=n-1; i++ ) sum=sum+*(a+i); // находим среднее арифметическое sum=sum/n; // печатаем полученное значение printf("sred_arif=%f\n", sum); // вывод одномерного динамического // массива на экран for (i=0; i<=n-1; i++) printf ("%.3f ", *(а+i)); printf("\n"); free(a); return 1; } |
Примечание. Для выделения динамической памяти под массив из n элементов использовалась библиотечная функция malloc():
Для ввода элементов массива как обычно использовалась функция scanf(). Вторым аргументов этой функции является адрес переменной, которая получает вводимое значение. В данном примере это адрес i-го элемента динамического массива a+i. При вычислении суммы значение i-го элемента получали с помощью записи
Вывод элементов массива осуществляется при помощи функции printf(), где для вывода элементов применялась та же форма записи.
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 2. Сформировать двухмерный динамический массив по закону .
Ход выполнения работы
1. Алгоритмы решения задач с использованием динамических массивов схожи с алгоритмами, использующими статические массивы.
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление вещ: *а ; цел: i, n // ввод количества строк массива ввод n // ввод количества столбцов массива ввод m выделить динамическую память под указатель a // формирование массива построчно для i=0 до n-1 шаг 1 для j=0 до m-1 шаг 1 aij=i+j все для j все для i // вывод массива построчно для i=0 до n-1 шаг 1 для j=0 до m-1 шаг 1 вывод aij все для j все_для i освободить выделенную под указатель a динамическую память | #include "stdio.h" #include "stdlib.h" int main ( ) { int *a; int i, j, m, n; //ввод n printf ("n=" ); scanf ("%i", &n); //ввод m printf ("m=" ); scanf ("%i", &m); //выделение динамической памяти под //целочисленный массив из n строк и //m столбцов a=(int*)malloc(n*m*sizeof(int)); //формирование динамического массива //построчно for ( i=0; i<=n-1; i++ ) for ( j=0; j<=m-1; j++ ) { *(a+i*m+j)=i+j; } //вывод динамического массива //построчно for (i=0; i<=n-1; i++) { for ( j=0; j<=m-1; j++ ) printf ("%i ", *(a+i*m+j)); printf("\n"); } //освобождение выделенной // динамической памяти free(a); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 3. Дан двухмерный динамический массив размера . Сформировать одномерный динамический массив, каждый элемент которого – произведение нечетных элементов соответствующего столбца двухмерного массива. Указать номер столбца с наименьшим произведением элементов.
Ход выполнения работы
1. Решение этой задачи было подробно рассмотрено в разделе «Двухмерные массивы».
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление вещ: *а,p,*b, цел: i, j, pmin, n, m // ввод количества строк массива ввод n // ввод количества столбцов массива ввод m выделить динамическую память под указатель a выделить динамическую память под указатель b // ввод массива построчно для i=0 до 6-1 шаг 1 // в цикле изменяется номер i строки // массива для j=0 до 4-1 шаг 1 // в цикле изменяется номер // столбца массива j // затем элемент вводится ввод аij все_для j все_для i // вычисление произведений для j=0 до 4-1 шаг 1 // в цикле изменяется номер j столбца // массива //находим произведение j-го столбца p=1 для i=0 до 6-1 шаг 1 // в цикле изменяется номер строки // массива i // находим нечетный элемент если остаток от дел aij на 2 =1 //изменяем произведение p=p*aij все_если все_для j b[j]=p все_для i //находим минимальный элемент //массива b p=b0 //номер минимального элемента pmin=0 для i=1 до 4-1 шаг 1 если p<bi p=bi pmin=i все_если все_для i // вывод массива a построчно для i=0 до 6-1 шаг 1 // в цикле изменяется номер i строки // массива для j=0 до 4-1 шаг 1 // в цикле изменяется номер j // столбца массива // затем этот элемент выводится на // экран вывод аij все_для j все_для i // вывод массива b для i=0 до 4-1 шаг 1 вывод bi все_для i печать pmin | #include "stdio.h" #include "stdlib.h" #include "math.h" int main() { float *a, p, *b; int i, j, pmin, n, m; //ввод n printf ("n=" ); scanf ("%i", &n); //ввод m printf ("m=" ); scanf ("%i", &m); //выделение динамической памяти под //целочисленный массив из n строк и //m столбцов a=( float *)malloc(n*m*sizeof(float)); b=( float *)malloc(m*sizeof(float)); // ввод динамического массива a // построчно for(i=0; i<=n-1; i++) { for (j=0; j<=m-1; j++) { printf ("a[%i][%i]=",i,j); scanf ("%f", a+i*m+j); } } // вычисление произведений for(j=0; j<=m-1; j++) { p=1; for (i=0; i<=n-1; i++) { if(fmod(*(a+i*m+j),2)==1) p=p*(*(a+i*m+j)); } *(b+j)=p; } //находим минимальный элемент массива //b p=*b; //нулевой элемент массива b pmin=0; for (i=0; i<=m-1; i++) { if(p>*(b+i)) { p=*(b+i); pmin=i; } } // вывод массива a построчно for (i=0; i<=n-1; i++) { for (j=0; j<=m-1; j++) printf ("%.2f ", *(a+i*m+j)); printf ("\n"); } printf ("\n"); // вывод массива b for (i=0; i<=m-1; i++) { printf ("%.2f ", *(b+i)); } printf ("\n"); printf ("№min=%i\n", pmin); free(a); free(b); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Л екция 14
Символы и строки
Цели:
ü получить представление о символьном типе данных и познакомиться с функциями, работающими с символами;
ü познакомиться с понятием строки в С++ и строчными функциями;
ü освоить методику написания алгоритмов с использованием символьных и строчных переменных, перевода таких алгоритмов на язык программирования С++ (с и без использования побитовых операций) и разработки соответствующего проекта в среде Visual C++ 6.0.
Символьный тип данных
Символьным типом данных на языке С++ является тип char. На машинном уровне символы представляются как целые числа. Для хранения символов и манипулирования ими каждому символу поставлен в соответствие его код – целое число. Существует несколько стандартов, определяющих, какие коды каким символам соответствуют. В С++ для кодировки символов используется стандарт ASCII, определяющий коды от 0 до 127. Для представления русских букв используется стандарт КОИ-8 или CP-1251. В этих стандартах русские буквы кодируются числами от 128 до 255. Таким образом, все символы могут быть представлены в одном байте. Значением переменных символьного типа может быть либо числовой код символа, либо символьная константа. Присваивание вида ch=’ab’; приведет к ошибке. Символьная константа – это один символ, заключенный в апострофы. Переменным символьного типа можно присвоить значение целого типа, выходящее за пределы диапазона то 0 до 255, но при этом компилятор преобразует это значение к значению в пределах от 0 до 255.
Объявление переменной символьного типа:
сhar ch; //ch – переменная символьного типа
сh=’а’; // символы на языке С++ заключаются в апострофы
ch=235; // такое присваивание возможно
Так как значением символьной переменной может быть целое число, то к переменным символьного типа применимы арифметические операции: +, -, *, /. Символьные переменные можно сравнивать при помощи операций отношения: >, <, >=, <=, = =, !=. При этом следует учитывать то, что все эти операции производятся с целыми числами – кодами символов. Таким образом, символьные переменные сравниваются через ASCII-коды соответствующих символов. Чем «старше» символ, тем больший ASCII-код ему соответствует.
Для работы с символами определены библиотечные функции, описанные в файлах conio.h, ctype.h и stdio.h. Некоторые из этих функций описаны в табл.8.
Таблица 8 | |
Функция | Форма обращения к функции и её краткое описание |
Файл ctype.h | |
isalnum | i = isalnum(int с); i – переменная типа int i не равно нулю, если значение с – код буквы или цифры (A...Z, a...z, 0...9); i = 0 – в противном случае |
isalalpha | i = isalalpha (int с); i – переменная типа int i не равно нулю, если значение с – код буквы или цифры (A...Z, a...z); i = 0 – в противном случае |
isascii | i = isascii (int с); i – переменная типа int i не равно нулю, если значение с – код ASCII, т.е. принимает значение от 0 до 127; i = 0 – в противном случае |
isdigit | i = isdigit (int с); i – переменная типа int i не равно нулю, если значение с – цифра (О... 9) в коде ASCII; i = 0 – в противном случае |
toascii | i = toascii (int с); i – переменная типа int i принимает значение в диапазоне от 0 до 127, т.е функция преобразует целое число с в символ кода ASCII |
Файл stdio.h | |
scanf | scanf ("%c", &ch); Функция форматированного ввода с клавиатуры ch – переменная типа char. Формат ввода "%c" означает, что с клавиатуры будет считываться один символ |
printf | printf ("%c", ch); Функция форматированного вывода ch – переменная типа char. Формат вывода "%c" означает, что на экран будет выведен один символ |
getchar | ch = getchar (); Считывает очередной символ, введенный с клавиатуры. Введенный символ отображается на экране ch – переменная типа char, которая получает введенное с клавиатуры значение |
putchar | putchar (ch); Выводит символ сh на экран ch – переменная типа char |
Файл conio.h | |
getch | ch = getch (); Считывает один символ, введенный с клавиатуры без отображения на экране ch – переменная типа char, которая получает введенное с клавиатуры значение |
Строки
Строка в языке С++ – это одномерный массив символьного типа char. Массив из n символов на самом деле будет содержать не n, а n-1 значащий символ. Причиной этого является то, что строка всегда содержит маркер или признак конца строки – это символ ’\0’. Строки на С++ заключаются в кавычки.
При объявлении строк нужно учитывать условие решаемой задачи. Если количество символов, содержащихся в строке, можно определить заранее, то можно работать со строкой как со статическим массивом символов. Если количество символов в строке определяется программно или вычисляется некоторым образом, то в этом случае разумнее использовать динамический массив символов.
Объявлять строки можно двумя способами:
1. Строка – динамический массив символов:
char * s;
При таком объявлении массива в программе нужно будет обязательно выделить динамическую память под указатель s. Далее можно работать со строкой как с динамическим массивом символов;
2. Строка – статический массив символов:
char s[500];
Обрабатываются строки, содержащие не более 499 символов, со строкой можно работать как со статическим массивом.
Поскольку строки являются одномерными массивами, то возможна их инициализация при объявлении:
char s[ ]= “строка”;
В данном случае строка s будет содержать 7 элементов (символов): ‘с’, ‘т’, ‘р’, ‘о’, ‘к’, ‘а’, ‘\0’. Однако невозможно присваивание вида
char s[ 20];
s=“строка”;
так как операция присваивания для строк не определена.
Если приходится работать с несколькими строками, то можно объявить массив строк – двухмерный массив символов.
char st [5][200];
Такой массив может содержать 5 строк, в каждой из которых может быть не более 199 символов.
По причине того что над строками в языке С++ не определены операции отношения, сложения и т.п., для этих целей разработаны библиотечные функции, описанные в головных файлах string.h и stdio.h (табл.9).
Таблица 9 | |
Файл string.h | |
Функция | Форма обращения к функции и её краткое описание |
1 | 2 |
atof | d = atof(str) ; Преобразует строку str в вещественное число d d – переменная типа double; str – строка, в которой записано вещественное число в виде набора символов–цифр и точки. Переводится часть строки, начиная с крайнего левого символа до первого появления символа, отличного от цифры или точки |
atoi | i = atoi(str); Преобразует строку str в десятичное целое число i i – переменная типа int; str – строка, в которой записано целое число в виде набора символов-цифр. Переводится часть строки, начиная с крайнего левого символа до первого появления символа, отличного от цифры |
atol | l = atol(str); Преобразует строку str в длинное десятичное целое число l l – переменная типа long; str – строка, в которой записано целое число в виде набора символов-цифр. Переводится часть строки, начиная с крайнего левого символа до первого появления символа, отличного от цифры |
itoa | itoa(v,str,baz); Преобразует целое v в строку str. При изображении числа используется основание системы счисления baz (2<=baz<=36) v – переменная типа int; str – строка; baz – переменная типа int |
ltoa | ltoa(v,str,baz); Преобразует длинное целое v в строку str. При изображении числа используется основание baz (2<=baz<=36) l – переменная типа long; str – строка; baz – переменная типа int |
strcat | strcat(str1,str2) ; Приписывает строку str2 в конец строки str1 (конкатенация строк) Результат в строке str1 |
strncat | strncat(str2,str1,kol); Приписывает kol символов строки str1 в конец строки str2 (конкатенация) kol – переменная типа int |
strchr | str2 = strchr(str1,сh); Ищет в строке str1 первое вхождение символа сh (тип char). В строку str2 записывается часть строки str1, начинающаяся с первого вхождения символа ch. Если такой символ не найден, то str2 равно NULL |
strrchr | str2 = strrchr(str1,сh); Ищет в строке str1 последнее вхождение символа сh (тип char). В строку str2 записывается часть строки str1, начинающаяся с последнего вхождения символа ch. Если такой символ не найден, то str1 равно NULL |
strcmp | i = strcmp(strl,str2); Сравнивает строки strl и str2. Результат заносится в переменную i (тип int) i<0, если strl<str2; i=0, если strl==str2; i>0, если strl>str2 (сравнение беззнаковое посимвольное) |
Продолжение таблицы 9 | |
1 | 2 |
strcpy | strcpy(str1, str2); Копирует символы строки str2 в строку str1 |
strncpy | strncpy(str2,str1,kol); Копирует kol символов строки str1 в строку str2 («хвост» отбрасывается или дополняется пробелами) kol – переменная типа int |
strlen | i = strlen(str); Вычисляет длину строки str без символа ‘\0’. Результат – в переменной i (типа unsigned int) |
Файл stdio.h | |
Функция | Форма обращения к функции и её краткое описание |
gets | gets(str); Считывает строку str как введенную с клавиатуры последовательность символов до первого нажатия клавиши <enter> |
puts | puts (str); Выводит строку str на экран |
Примечание. Строку можно вводить с клавиатуры с помощью функции gets() и функции scanf(). При этом нужно помнить, что если первая функция заполняет строку символами до первого нажатия клавиши <enter>, то вторая записывает в строку введенные с клавиатуры символы до появления первого пробела.
При решении задач, связанных с обработкой текста, с заданным текстом работают как со строкой. Таким образом, алгоритмы решения подобных задач основаны на алгоритмах обработки массивов. В данном случае это массивы символов.
Пример 1. Дан текст. Распечатать текст в обратном порядке.
Ход выполнения работы
1. Алгоритмы решения задач с использованием строк основаны на алгоритмах обработки одномерных массивов.
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление симв: *str; цел: i, n, // ввод количества символов текста ввод n выделить динамическую память под указатель str ввод строки str //в цикле проверяется каждый символ, //начиная с последнего для i= strlen(str) до 0 шаг -1 печать stri все для i освободить выделенную под указатель str динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" int main ( ) { char *str; int n; unsigned int i; //ввод n printf ("n=" ); scanf ("%i", &n); //выделяется динамическая память str=(char*)malloc(n); //ввод строки gets(str); for ( i= strlen(str); i>=0; i-- ) { printf("%c",*(str+i)); } printf("\n"); //освобождение выделенной //динамической памяти free(str); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 2. Дан текст. Подсчитать, сколько в нем слов. Словом считать набор символов, не содержащий символов: ‘.’ , ‘!’ , ‘?’ , ‘,’ , ‘;’ , ‘:’, ‘ ’. Подсчитать количество слов, содержащих 5 символов.
Ход выполнения работы
1. Для подсчета количества символов, содержащихся в каждом слове текста, необходимо определить начало и конец слова, т.е. определить позиции первого и последнего символов каждого слова. Найдя их разность, сравним её с числом 5. Если нужное слово найдено, то увеличим некоторый счетчик на 1. Первый символ слова определим по правилу: если в позиции i находится один из символов ‘.’ , ‘!’ , ‘?’ , ‘,’ , ‘;’ , ‘:’ , ‘ ’, а в позиции i+1 нет ни одного из них, то, с позиции i+1 начинается слово. Последний символ слова определим по правилу: если в позиции i нет ни одного из символов ‘.’ , ‘!’ , ‘?’ , ‘,’ , ‘;’ , ‘:’ , ‘ ‘, а в позиции i+1 находится один из них, то, начиная с позиции i, слово заканчивается.
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление симв: *str; цел: i, n, bw, ew, count, count_5 // ввод количества символов текста ввод n выделить динамическую память под указатель str ввод строки str count =0, count_5=0 //в цикле проверяется каждый символ для i=0 до strlen(str) шаг 1 //определяем первый символ слова пока stri=='.' или stri=='!' или stri=='?' или stri==',' или stri==';' или stri==':' или stri==' ' и i<=strlen(str) //пропускаем эти символы i++ все_пока //запоминаем позицию начала слова bw=i //определяем последний символ слова пока stri!='.' и stri!='!' и stri!='?' и stri!=',' и stri!=';' и stri!=':' и stri!=' ' и i<=strlen(str) //пропускаем символы слова i++ все_пока //запоминаем позицию конца слова ew=i-1 если ew-bw>=0 count++ все_если если ew-bw+1==5 count_5++ все_если все для i вывод count вывод count_5 вывод строки str освободить выделенную под указатель str динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" int main ( ) { char *str; int n, bw, ew, count, count_5; unsigned int i; //ввод n printf ("n=" ); scanf ("%i", &n); //выделяется динамическая память str=(char*)malloc(n); //ввод строки gets(str); count =0, count_5=0; for ( i=0; i<=strlen(str); i++ ) { //определяем первый символ //слова while((*(str+i)=='.' || *(str+i)=='!' || *(str+i)=='?' || *(str+i)==',' || *(str+i)==';' || *(str+i)==':' || *(str+i)==' ') && i<=strlen(str)) //пропускаем эти символы i++; //запоминаем позицию начала //слова bw=i; //определяем последний символ //слова while(*(str+i)!='.' && *(str+i)!='!' && *(str+i)!='?'&& *(str+i)!=',' && *(str+i)!=';' && *(str+i)!=':' && *(str+i)!=' '&& i<=strlen(str)) //пропускаем символы //слова i++; //запоминаем позицию конца //слова ew=i-1; if(ew-bw>=0) count++; if(ew-bw+1==5) count_5++; } //вывод count printf(“количество слов в тексте = %i\n”,count); //вывод count_5 printf(“количество слов из 5 символов = %i\n”,count_5); //вывод строки str puts(str); //освобождение выделенной динамической памяти free(str); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Запишем те же алгоритм и программу с использованием статического массива:
Алгоритм | Программа |
объявление симв: str[200]; цел: i, bw, ew, count, count_5 ввод строки str count =0, count_5=0 //в цикле проверяется каждый символ для i=0 до strlen(str) шаг 1 //определяем первый символ слова пока str[i]=='.' или str[i]=='!' или str[i]=='?' или str[i]==',' или str[i]==';' или str[i]==':' или str[i]==' ' и i<=strlen(str) //пропускаем эти символы i++ все_пока //запоминаем позицию начала слова bw=i //определяем последний символ слова пока str[i]!='.' и str[i]!='!' и str[i]!='?' и str[i]!=',' и str[i]!=';' и str[i]!=':' и str[i]!=' ' и i<=strlen(str) //пропускаем символы слова i++ все_пока //запоминаем позицию конца слова ew=i-1 если ew-bw>=0 count++ все_если если ew-bw+1==5 count_5++ все_если все для i вывод count вывод count_5 вывод строки str | #include "stdio.h" #include "stdlib.h" #include "string.h" #define n 200 int main ( ) { char str[n]; int bw, ew, count, count_5; unsigned int i; //ввод строки gets(str); count =0, count_5=0; for ( i=0; i<=strlen(str); i++ ) { //определяем первый символ //слова while((str[i]=='.' || str[i]=='!' || str[i]=='?'|| str[i]==',' || str[i]==';' || str[i]==':' || str[i]==' ') && i<=strlen(str)) //пропускаем эти символы i++; //запоминаем позицию начала //слова bw=i; //определяем последний символ //слова while(str[i]!='.' && str[i]!='!' && str[i]!='?'&& str[i]!=',' && str[i]!=';' && str[i]!=':' && str[i]!=' ' && i<=strlen(str)) //пропускаем символы //слова i++; //запоминаем позицию конца //слова ew=i-1; if(ew-bw>=0) count++; if(ew-bw+1==5) count_5++; } //вывод count printf(“количество слов в тексте = %i\n”,count); //вывод count_5 printf(“количество слов из 5 символов = %i\n”,count_5); //вывод строки str puts(str); return 1; } |
Примечание. Синтаксис программы, использующий статический массив, несколько проще и более понятен при чтении. Однако использование динамических массивов делает решение более гибким, поскольку в этом случае имеется возможность динамического изменения длины строки в ходе выполнения программы.
Пример 3. Дан текст. Распечатать текст по предложениям. Предложением считать набор символов, заканчивающийся одним из символов: ‘.’ , ‘!’ , ‘?’.
Ход выполнения работы
1. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление симв: *str; цел: i, j, n, bp, ep // ввод количества символов текста ввод n выделить динамическую память под указатель str ввод строки str //в цикле проверяется каждый символ для i=0 до strlen(str) шаг 1 //определяем первый символ // предложения пока stri=='.' или stri=='!' или stri=='?' и i<=strlen(str) //пропускаем эти символы i++ все_пока //запоминаем позицию начала // предложения bp=i //определяем последний символ //предложения пока stri!='.' и stri!='!' и stri!='?' и i<=strlen(str) //пропускаем символы слова i++ все_пока //запоминаем позицию конца //предложения ep=i //печатается очередное предложение для j= bp до ep шаг 1 печать strj все_для j все для i освободить выделенную под указатель str динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" int main ( ) { char *str; int j, n, bp, ep; unsigned int i; //ввод n printf ("n=" ); scanf ("%i", &n); //выделяется динамическая память str=(char*)malloc(n); //ввод строки gets(str); for ( i=0; i<=strlen(str); i++ ) { //определяем первый символ // предложения while((*(str+i)=='.' || *(str+i)=='!' || *(str+i)=='?') && i<=strlen(str)) //пропускаем эти символы i++; //запоминаем позицию начала //предложения bp=i; //определяем последний символ //предложения while(*(str+i)!='.'&&*(str+i)!='!'&& *(str+i)!='?'&& i<=strlen(str)) //пропускаем символы //слова i++; //запоминаем позицию конца // предложения ep=i; //печатается очередное //предложение for(j=bp;j<=ep;j++) //выводится j-ый символ //предложения printf("%c",*(str+j)); printf("\n"); } //освобождение выделенной //динамической памяти free(str); return 1; } |
2. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 4. Дан текст. Распечатать позиции, начиная с которых в тексте встречается заданное слово. Определение слова такое, как и в предыдущих примерах.
Ход выполнения работы
1. Написать программу, соответствующую алгоритму
Алгоритм | Программа |
объявление симв: *text,*slovo; цел: i, j, n, bw, ew, flag // ввод количества символов текста ввод n выделить динамическую память под указатели text, slovo ввод text ввод slovo //в цикле проверяется каждый символ для i=0 до strlen(text) шаг 1 //определяем первый символ слова пока texti=='.' или texti=='!' или texti=='?' или texti==',' или texti==';' или texti==':' или texti==' ' и i<=strlen(text) //пропускаем эти символы i++ все_пока //запоминаем позицию начала слова bw=i //определяем последний символ слова пока texti!='.' и texti!='!' и texti!='?' и texti!=',' и texti!=';' и texti!=':' и texti!=' ' и i<=strlen(text) //пропускаем символы слова i++ все_пока //запоминаем позицию конца слова ew=i-1 //сравниваем slovo и слово текста если ew-bw+1== strlen(slovo) flag=1;//длины слов совпадают для j= 0 до ew-bw шаг 1 если textbw+j !=slovoj flag=0;//слова не совпадают выход из цикла по j все_если все_для j все_если если flag==1 flag=0 печать bw все_если все для i освободить выделенную под указатели text, slovo динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" int main ( ) { char *text,*slovo; int j, n, bw, ew, flag; unsigned int i; //ввод n printf ("n=" ); scanf ("%i", &n); //выделяется динамическая память text=(char*)malloc(n); slovo=(char*)malloc(20); //ввод строк puts("text="); gets(text); puts("slovo="); gets(slovo); for ( i=0; i<=strlen(text); i++ ) { //определяем первый символ слова while((*(text+i)=='.' || *(text+i)=='!' || *(text+i)=='?'|| *(text+i)==',' || *(text+i)==';' || *(text+i)==':' || *(text+i)==' ') && i<=strlen(text)) //пропускаем эти символы i++; //запоминаем позицию начала //слова bw=i; //определяем последний символ // слова while(*(text+i)!='.'&&*(text+i)!='!' && *(text+i)!='?'&& *(text+i)!=','&& *(text+i)!=';' &&*(text+i)!=':'&& *(text+i)!=' ' && i<=strlen(text)) //пропускаем символы слова i++; //запоминаем позицию конца //слова ew=i-1; if(ew-bw+1== strlen(slovo)) { flag=1; for(j=0;j<=ew-bw;j++) if(*(text+bw+j)!=*(slovo+j)) { flag=0; break; } } if(flag==1) { flag=0; printf("pos=%i\n",bw); } } //освобождение выделенной //динамической памяти free(text); free(slovo); return 1; } |
2. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 5. Дан текст в виде набора 0 и 1 – некоторое число в двоичной системе счисления. Представить это число в десятичной системе счисления.
Ход выполнения работы
1. Алгоритм перевода числа из двоичной системы счисления в десятичную систему счисления поясним на примере.
Наименование | Разряды в двоичной системе счисления | Число | ||||||
6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
Число в двоичной системе счисления, записанное по разрядам | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 11010012 |
Слагаемые для получения числа в десятичной системе счисления, соответствующие каждому разряду | 1·26 | 1·25 | 0·24 | 1·23 | 0·22 | 0·21 | 1·20 | 10510 |
Таким образом, 11010012=1·20+0·21+0·22+1·23+0·24+1·25+1·26 =1+8+32+64=10510.
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление вещ: *num_bin; цел: i, j, n, num_dec // ввод количества символов текста ввод n выделить динамическую память под указатель num_bin ввод num_bin j=strlen(num_bin)-1 num_dec=0 //в цикле проверяется каждый символ для i=strlen(num_bin) до 0 шаг -1 //сравниваем символ текста с // символом ‘1’ если num_bini = = ‘1’ num_dec=num_dec+2j-i все_если все для i печать num_dec освободить выделенную под указатель num_bin динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" #include "math.h" int main ( ) { char *num_bin; int n, num_dec; unsigned int i; //ввод n printf ("n=" ); scanf ("%i", &n); //выделяется динамическая память num_bin=(char*)malloc(n); //ввод строки puts("num_bin="); gets(num_bin ); //определяется количество разрядов j=strlen(num_bin)-1; //инициализируется значение в //десятичной системе num_dec=0; for ( i= strlen(num_bin); i>=0; i-- ) { // сравниваем символ текста с // символом ‘1’ if(*(num_bin+i)= =’1’) { num_dec=num_dec+pow(2, j-i); } } printf("num_dec=%i\n ",num_dec); //освобождение выделенной //динамической памяти free(num_bin); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Пример 6. Дано целое число в десятичной системе счисления. Представить это число в двоичной системе счисления.
Ход выполнения работы
1. Алгоритм перевода числа из десятичной системы счисления в двоичную осуществляется путем деления десятичного числа на 2. Запоминается остаток, и полученное частное снова делится на 2. Эта процедура повторяется до тех пор, пока полученное на некотором шаге частное не станет равным 0 или 1. Записав остатки от деления в обратном порядке, получим число в двоичной системе счисления (в программе результат помещается в строку), например:
105 2
1 52 2
0 26 2
0 13 2
1 6 2
0 3 2
1 1
Таким образом, 10510 = 11010012 (порядок записи остатков указан стрелкой). Решить данную задачу можно было бы с использованием операции деления, т.е. непосредственно по приведенному алгоритму. Воспользовавшись поразрядными операциями и понятием маски можно упростить решение задачи. Для этого установим начальное значение маски в 1. При помощи операции & проверим, совпадает ли самый правый бит с маской или нет. Если совпадает, то в текущую позицию строки записываем 1, в противном случае – 0. Затем сдвигаем 1 в маске на одну позицию влево. Опять происходит описанная выше проверка и т.д. Количество проверок должно совпадать с количеством бит переменной (десятичным числом), т.е. с размером типа этой переменной, умноженного на 8 (количество байт, занимаемых переменной в ОП, умножаем на количество бит, содержащихся в одном байте).
2. Написать программу, соответствующую алгоритму:
Алгоритм | Программа |
объявление вещ: *num_bin; цел: i, n, num_dec, mask=1 ввод num_dec n=sizeof(num_dec)*8 выделить динамическую память под указатель num_bin из n+1 символов //в цикле проверяется каждый бит для i=1 до n+1 шаг 1 //проверяем i-ый бит числа num_dec //на наличие 1 если num_dec&mask num_binn+1-i = = ‘1’ иначе num_binn+1-i = = ‘0’ все_если сдвиг mask на 1 разряд влево все для i печать num_bin освободить выделенную под указатель num_bin динамическую память | #include "stdio.h" #include "stdlib.h" #include "string.h" #include "math.h" int main ( ) { char *num_bin; int num_dec, mask=1; int n, i; //ввод десятичного числа printf("num_dec="); scanf("%d",&num_dec); n=sizeof(num_dec)*8; //выделяется динамическая память num_bin=(char*)malloc(n+1); for ( i= 1; i<=n+1; i++ ) { // проверяем i-ый бит числа // num_dec на наличие 1 if(num_dec&mask) //i–ый бит числа num_dec //содержит 1 *(num_bin+n+1-i)='1'; else //i–ый бит числа num_dec //содержит 0 *(num_bin+n+1-i)='0'; //изменение маски mask=mask<<1; } printf("num_bin="); // нули до первой 1 не печатаются for(i= 1; i<=n+1; i++) if(*(num_bin+i)!=0) break; // печатается число в двоичной системе for( ; i<=n; i++) printf("%c",*(num_bin+i)); printf("\n"); //освобождение выделенной //динамической памяти free(num_bin); return 1; } |
3. Создать проект и реализовать данную задачу в среде Visual C++ 6.0.
Л екция 15
Структуры
Цели:
ü получить представление о понятиях «структурный тип», «структура»;
ü освоить методику написания алгоритмов с использованием динамических и статических массивов структур, перевода таких алгоритмов на язык программирования С++ и разработки соответствующего проекта в среде Visual C++ 6.0.
Понятие структуры
При решении практических задач очень часто приходится сталкиваться с объектами, которые невозможно описать переменной одного типа. Для описания такого рода объектов требуется несколько переменных различного типа. Для решения этой проблемы в языке С++ используют понятие «структура» – это совокупность переменных различных типов, объединённых в одну переменную. Элементы структуры называются полями. В качестве полей структуры могут выступать скалярные величины, массивы, а также другие структуры. Таким образом, структурный тип задает внутреннее строение определяемых с его помощью структур-переменных. В отличие от массива, всегда состоящего из однотипных элементов, компоненты структуры-переменной могут быть разных типов и все должны иметь различные имена. Из определения структуры понятно, что заполнение и обработка структур производится только поэлементно – операции над структурами в языке С++ не определены, т.е. ввод-вывод элементов структуры-переменной осуществляется при помощи стандартных функций printf() и scanf(). Становится ясно, что объём оперативной памяти, которую занимает структура-переменная, будет равен суммарному объёму памяти, который занимают все элементы такой структуры.
Описание структуры производится при помощи спецификатора объявления структур: struct. Описание структуры:
struct <имя_структурного_типа>
{
<имя_типа_данных_1> <поле_1>;
<имя_типа_данных_2> <поле_2>;
…
<имя_типа_данных_N> <поле_N>;
};
Объявление структуры-переменной:
struct <имя_структурного_типа> <имя_структуры–переменной>;
Например, структура «товар» содержит поля:
название товара
закупочная цена
торговая наценка в процентах
объем партии товара
дата поступления партии товара
В соответствии со смыслом поля могут иметь любой из типов данных, допустимых в языке. Так как наименований товаров на складе может быть много, то для определения отдельных структур, содержащих сведения о конкретных товарах, нужно ввести структурный тип. Для данного примера его можно определить так:
struct tovar
{
char name[50]; // Наименование
float price ; // Цена оптовая
float percent; // Наценка в %
int vol; // 06ъем партии
char date[9] ; // Дата поставки партии
};
struct tovar tv;
В данном примере struct – спецификатор структурного типа; tovar – имя структурного типа; tv – структура-переменная.
В фигурных скобках размещаются описания элементов, которые будут входить в каждый объект типа tovar.
Для того чтобы получить доступ к полю структуры, необходимо записать имя структуры-переменной, после имени поставить точку, а затем написать имя этого поля:
gets(tv.name); // ввод с клавиатуры поля name
tv.price = 1234.56; // присваивание полю price значения 1234.56
scanf("%f",&tv.percent); // ввод с клавиатуры вещественного значения
// по адресу поля percent
Дата добавления: 2019-11-25; просмотров: 499; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!