Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Sb98333

.pdf
Скачиваний:
9
Добавлен:
13.02.2021
Размер:
371.01 Кб
Скачать

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

Задания по теме.

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

2.В описаниях функции calloc() сказано, что она выделяет память и устанавливает значения элементов массива в 0 (заполняет массив нулями). Проверить это утверждение для одномерных и двумерных массивов (квадратных матриц) с количеством элементов в строке от 5 до 15.

3.Дана матрица целочисленных значений размерами N × M. Получить по-

следовательность B1...Bn где Bk –это число отрицательных элементов в k-ой строке. Для создания массива использовать генератор случайных чисел.

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

5.Из прямоугольной целочисленной матрицы с заданными размерами вычеркнуть строку с максимальной суммой элементов. Для создания массива использовать генератор случайных чисел.

6.Значения элементов двумерного массива из M строк и N столбцов скопировать в одномерный массив размером M × N. Копирование проводить по строкам начиная с первой (а в ней — с крайнего левого элемента).

7.Значения элементов двумерного массива из M строк и N столбцов скопировать в одномерный массив размером M × N. Копирование проводить по столбцам начиная с первого (а в нем — с самого верхнего элемента).

8.Сформировать одномерный массив из максимальных элементов строк двумерного массива из M строк и N столбцов.

9.Сформировать одномерный массив из минимальных элементов столбцов двумерного массива из M строк и N столбцов.

21

10. Сформировать двумерный массив из одномерного, разделив исходный массив на строки, начинающиеся с заданного числа.

ТЕМА 6. ФУНКЦИИ

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

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

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

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

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

В приводимой далее программе описаны две функции:

функция read_array() выделяет динамическую память для массива, обеспечивает ввод элементов массива с клавиатуры и возвращает адрес первого элемента массива. Ее аргументом является целое число (количество элементов массива), а возвращаемым значением – указатель на созданный массив. Если динамическая память не была выделена, то функция возвращает NULL.

функция show_array() выводит на экран элементы массива. Она не возвращает значение и имеет два аргумента: целое число (количество элементов массива) и указатель на массив целых чисел.

22

#include <stdio.h> #include <stdlib.h>

int *read_array(int k)

{

inti; int *m;

if((m=(int*)calloc(k,sizeof(int)))!=NULL)

{

printf("Enter %d values:\n",k); for(i=0; i< k; i=i+1) scanf("%d",&m[i]); printf("Reading OK\n");

}

else m=NULL; return m;

}

void show_array(int k, int *m)

{

inti;

for(i=0;i<k;i=i+1) printf("%d ",m[i]);

}

int main()

{

int n;

int *m1=NULL;

printf("Number of elements to be entered: "); scanf("%d",&n);

if((m1=read_array(n))!=NULL)

{

printf("\nThe values entered are: \n"); show_array(n,m1);

free(m1);

m1=NULL;

}

else printf("ERROR at memory allocation!\n"); return 0;

}

В основной программе (функции main()) вводится число элементов массива и после вызова функций read_array() и show_array() освобождается динамическая память, выделенная для массива.

Задания по теме.

1. Рассчитать площадь треугольника, образованного пересечением трех прямых с параметрами a и b (y = ax + b). Для реализации алгоритма написать функции определения координат точек пересечения (intersect_x() и

intersect_y()), вычисления длины отрезков (side_length(x1,y1,x2,y2)) и

23

вычисления площади по формуле Герона через длины сторон. Перед расчетом площади проверить существование треугольника.

2.Перевести число, заданное в десятичной системе, в двоичную систему, используя функцию перевода.

3.Получить все шестизначные счастливые номера. Счастливым называется номер, у которого сумма первых трех цифр номера равна сумме последних трех цифр. Использовать функцию для расчета суммы цифр трехзначного числа.

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

5.Задан одномерный массив из M элементов. Сформировать двухмерный массив N×N, используя функцию преобразования любого одномерного массива

вдвухмерный массив размерами N×N с добавлением нулевых элементов.

6.Задан одномерный массив из N2элементов. Сформировать двухмерный массив N×N, в котором элементы увеличиваются слева направо, используя функции сортировки и преобразования одномерного массива в двухмерный массив.

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

8.Сгенерировать массив случайных чисел от 0 до 50 и определить количество четных и нечетных чисел в этом массиве. Для определения четных и нечетных чисел использовать функции.

9.Написать функцию вычисления определителя для квадратной матрицы. Для создания двумерного массива использовать генератор случайных чисел. Размер массива (матрицы) задается пользователем.

10.Написать функцию транспонирования матрицы размером N×M. Для создания двумерного массива использовать генератор случайных чисел.

ТЕМА 7. РАБОТА СО СТРОКАМИ

Строка в Си представляет собой массив символов (char). В кодировке ASCII один символ занимает в памяти один байт. Размер памяти для хранения символа можно получить с помощью функции sizeof(char). Строка заканчивается специальным символом-ограничителем с «нулевым» кодом (символ '\0'), поэтому полезных символов в ней на 1 меньше, чем количество символов, хранящихся в памяти. Наличие символа-ограничителя помогает понять, где

24

заканчивается строка (в отличие от числовых массивов, у которых нет ограничителя).

В программе строки могут определяться в виде строковой константы

(″hello″, кавычки не входят в строку), массива символов (chars2[10], начальное значение символов строки не определено) и через указатель на символьный тип (char *s3). В последнем варианте определения строки место для хранения символов не предусмотрено, для ее использования потребуется выделение памяти.

Для работы со строками в составе стандартной библиотеки существуют функции, описанные в заголовочном файле string.h. При выводе строк на экран (в стандартный поток вывода stdout) применяются функции puts() и printf(). Функция puts() позволяет вывести строку как строковый литерал без указания спецификатора формата, а в функции printf() при выводе строки используется спецификатор формата %s.

Для ввода строк с клавиатуры можно применять посимвольный ввод или чтение из стандартного потока ввода (stdin) как из файла.

Для посимвольного ввода строки применяют функцию getchar(), которая возвращает ASCII-код символа, введенного с клавиатуры. Обычно строку вводят до символа перевода строки ('\n', ASCII-код 10) или до достижения максимального заданного количества символов. После этого в конец сформированной строки принудительно ставят символ-ограничитель '\0'. Такой вариант ввода строки далее оформлен в виде функции, аргументами которой являются указатель на строку и максимальный размер строки.

#include <stdio.h> #define MAXLEN 16

void read_str(char *str, int n)

{

int i; i=0;

while(((*str=getchar()) !='\n') && (i<n-1)){ str++;

i++;

}

*str='\0';

}

int main()

{

char str1[MAXLEN];

printf("Please enter string: "); read_str(str1, MAXLEN); printf("%s\n",str1);

return 0;

}

25

Строки (текст) хранят, как правило, в файле. В отличие от переменной, файл существует вне конкретной программы. Он имеет имя, тип и спецификацию пути к каталогу, где размещается файл. Функции для файлового ввода и вывода размещаются в стандартной библиотеке языка Си stdio.h. Чтобы выполнять файловые операции чтения и записи, программа должна получить указатель на соответствующий файл. Указатель на файл объявляется как

FILE *fp;

Значение указателю на файл присваивается при выполнении операции от-

крытия файла fp= fopen(constchar *имя_файла, constchar *режим);

Основными режимами при работе с текстовыми файлами являются: "w"−открытие файла только для записи (если файл существует, его содер-

жимое очищается);

"r"−открытие существующего файла только для чтения;

"a"–открытие файла длядобавления (запись в конец файла; если файл не существует, то создается новый файл).

Для работы с файлами существуют функции fprintf() и fscanf(), позволяющие задать входной/выходной формат аналогично printf() и scanf().

Функция fgets() осуществляет чтение строки из файла. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() следующие:

fgets(char *string, int num, FILE *filestream), где

string– указатель на массив, в который сохраняется считанная строка; num– максимально допустимая длина считываемой строки, включая нуле-

вой символ;

filestream– указатель на файл.

Если в качестве filestream указать имя стандартного потока ввода (stdin), то fgets() будет считывать строки при вводе с клавиатуры. При этом после последнего прочитанного символа в массив также будет занесен признак конца строки (нулевой символ).

Примеры операций с текстовыми файлами показаны в следующей программе:

#include <stdio.h> #include <stdlib.h> #define MAXLEN 128

int main()

{

char str[MAXLEN]; char strout[MAXLEN]; char s1[MAXLEN];

char s2[8],s3[8],s4[8]; int i, x, y, z;

26

FILE *datafile;

FILE *outfile;

if((datafile=fopen("data0.txt","r"))!=NULL)

{

outfile=fopen("outdata.txt", "w"); i=0; while(fgets(str,MAXLEN,datafile)!=NULL)

{

sscanf(str,"%s %s %s %s", s1, s2, s3, s4); printf("String%d: %s\n", i, s1); x=atoi(s2);

y=atoi(s3);

z=atoi(s4);

printf("values set %d: %d %d %d\n", i, x, y, z); sprintf(strout,"%d",x+y+z);

fprintf(outfile, "String %d: %s: %s\n", i, s1, strout); i=i+1;

}

fclose(outfile);

fclose(datafile);

}

else puts("Cannot open datafile!"); return 0;

}

В этой программе используются два текстовых файла: входной data0.txt (указатель datafile) и выходной outdata.txt (указатель outfile). Будем предполагать, что входной файл содержит следующие строки:

one 10 20 30 two 11 22 33 three 12 21 31

Строки из этого файла циклически считываются функцией fgets в переменную str, а затем с помощью функции sscanf() из нее извлекаются четыре значения в s1, s2, s3, s4. Далее для преобразования символьного представления чисел в целое десятичное число применяется функция atoi(), описанная в заголовочном файле stdlib.h. В конце цикла функция fprintf() записывает в выходной файл данные в соответствии со спецификатором формата. Этот файл будет содержать следующие строки:

String 0: one 60 String 1: two 66 String 2: three 64

После завершения работы с файлом он должен быть закрыт. Для этого применяется функция fclose(). Параметром этой функции является указатель на структуру FILE, ранее полученный при открытии файла.

Для знакомства с другими часто используемыми функциями работы со строками рассмотрим решение следующей задачи. В файле построчно записаны английские названия месяцев в календарном порядке. Требуется отсортировать список месяцев в алфавитном порядке и результат записать в другой файл.

Пусть исходный файл называется calendar.txt, итоговый файл – sorted.txt.

27

Если исходный файл удается открыть, то формируется динамический массив, в который считываются стоки из исходного файла с помощью функции fgets(). При этом из каждой прочитанной строки убирается символ перевода строки. Для массива строк память выделяется в два этапа: сначала выделяются 12 указателей для хранения ссылок на названия месяцев, а затем выделяется память для хранения названий месяцев, по 10 символов для каждого названия. Каждое выделение памяти сопровождается проверкой на успешность выделения. Если для очередной строки память выделить не удается, очищается вся ранее выделенная память для строк и выдается сообщение об ошибке.

После формирования массива он сортируется в алфавитном порядке с помощью функции sort_array(), которая описана в начале программы. Аргументами этой функции являются неупорядоченный массив строк и число элементов массива. При упорядочении используются библиотечные функции копирования строк strcpy() и лексикографического сравнения строк strcmp(). Первая функция копирует из массива строку по заданному адресу tmp, включая нулевой символ. Копируемая строка и строка назначения не должны перекрываться в памяти. Вторая функция побайтно сравнивает строку tmp с остальными строками массива. Она возвращает 0, если сравниваемые строки идентичны, положительное число – если строки отличаются и код первого отличающегося символа в первой строке больше кода символа на той же позиции во второй строке, отрицательное число – если строки отличаются и код первого отличающегося символа в первой строке меньше кода символа на той же позиции во второй строке. Поскольку сортировка выполняется по возрастанию, то значение функции strcmp() сравнивается с положительным числом. Если это условие выполняется, то осуществляется перестановка соседних строк массива. После первого прохода в последнем элементе массива будет строка с наибольшим значением кода. На последующих проходах по такому же принципу анализируются оставшиеся элементы массива. Процесс сортировки заканчивается, когда строк массива для анализа не останется.

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

#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LEN 12

28

#define MONTH 12

/* Sorting string array by instertion method */ void sort_array(char **arr, int n)

{

char tmp[MAX_LEN]; int i,j;

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

{

strcpy(tmp,arr[i]); for(j=i-1;(j>=0)&&(strcmp(arr[j],tmp)>0);j=j-1)

{

strcpy(arr[j+1],arr[j]);

}

strcpy(arr[j+1],tmp);

}

}

int main()

{

char **str_array=NULL; FILE *infile, *outfile; int i,count,key,slen;

key=1;

if((infile=fopen("calendar.txt","r"))!=NULL)

{

if((str_array=(char**)malloc(MONTH*sizeof(char*)))!=NULL)

{

count=0;

for(i=0;(i<MONTH)&&(key==1);i++)

{

if((str_array[i]=(char*)malloc(MAX_LEN*sizeof(char)))!=NULL)

{

fgets(str_array[i],MAX_LEN,infile); slen=strlen(str_array[i]); str_array[i][slen-1]='\0';

}

else

{

count=i;

key=0;

puts("Error at string allocation!"); for(i=0;i<count;i++)

{

free(str_array[i]); str_array[i]=NULL;

}

}

}

fclose(infile); sort_array(str_array,MONTH); if((outfile=fopen("sorted.txt","w"))!=NULL)

{

i=0; while((str_array[i]!=NULL)&&(i<MONTH))

{

fprintf(outfile,"%s\n",str_array[i]); free(str_array[i]);

29

str_array[i]=NULL; i++;

}

fclose(outfile);

}

else

{

puts("Results not saved!"); i=0;

while((str_array[i]!=NULL)&&(i<MONTH))

{

free(str_array[i]); str_array[i]=NULL; i++;

}

}

free(str_array); str_array=NULL;

}

else puts("Error at memory allocation!");

}

else puts("Error opening data file!"); return 0;

}

Задания по теме.

1.Разработать алгоритм и написать функцию count() для подсчета количества вхождений заданной подстроки в строку.

2.Разработать алгоритм и написать функцию split() для формирования массива подстрок в результате разделения строки на части по заданному символу.

3.Задана произвольная строка, содержащая цифры. Заменить все цифры на заданный символ.

4.Задана произвольная фраза (слова с разделителями). Определить количество слов, начинающихся с заданной буквы.

5.Из заданной фразы (слова с разделителями) удалить все символыразделители, отсортировать символы получившейся строки в обратном алфавитном порядке.

6.Подсчитать количество вхождений каждой буквы строки в эту строку.

7.Задана произвольная фраза (слова с разделителями). Переставить слова так, чтобы они следовали в алфавитном порядке.

8.Задана произвольная фраза (слова с разделителями). Подсчитать количество символов-разделителей.

9.Задана произвольная фраза (слова с разделителями). Подсчитать количество вариантов символов-разделителей.

10.В файле записаны произвольные строки. Сформировать динамические массивы слов по строкам. Для каждой строки посчитать длину, количество слов

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]