А.А. Белеванцев, С.С. Гайсарян, Л.С. Корухова, Е.А. Кузьменкова, В.С. Махнычев. Семинары по курсу Алгоритмы и алгоритмические языки (1108027), страница 7
Текст из файла (страница 7)
Таким образом, в результатевыполнения указанного фрагмента будет напечатано:11 -5 36.1.4. Передача массива в функциюПри передаче массива в функцию используется то, что имя массива являетсяконстантным указателем на его нулевой элемент: при указании в качестве параметраимени массива в функцию фактически передается по значению этот указатель (т.е. копияадреса начала той области памяти, в которой находятся элементы массива).
Из типауказателя также известно, сколько места занимает каждый элемент массива, что позволяетобратиться к любому элементу массива. Но информация о количестве элементов массиватеряется, поэтому размер массива следует передавать в функцию через дополнительныйпараметр. Например, рассмотрим функцию вычисления суммы элементов целочисленногомассива из n элементов. Ниже приведены два эквивалентных описания прототипа этойфункции:int sum(int t[], int n);Здесь t – имя массива, при этом наличие квадратных скобок обязательно.int sum (int *t, int n);Здесь t – указатель на целое (на элемент массива с индексом 0).Вызов функции:intint…x =y =z =a[10];x, y, z;sum(a, 10); // сумма элементов всего массиваsum(a, 5); // сумма элементов первой половины массиваsum(a + 5, 5); // сумма элементов второй половины массиваЗадача 4. Описать функцию вычислениявещественных массивов из n элементов.скалярногоdoublescalar (double x[], double y[], int n) {double s = 0.0;int i;for (i = 0; i < n; i++) {s += x[i] * y[i];}return s;}29произведениядвух6.2.
СтрокиПонятие строки. Строковые константы (строковые литералы). Ввод и вывод строк.Работа со строками. Задачи.6.2.1. Строки и строковые константыПод строкой в языке Си понимается последовательность символов,оканчивающаяся символом с кодом 0 ('\0'). В языке нет специального строкового типа,для хранения строк используются массивы типа char, signed char, unsignedchar .
Поэтому строки, по сути, являются массивами символов, отличающимися отобычных массивов обязательным наличием символа '\0' в конце строки. Любаяпрограмма обработки строк определяет конец строки именно по данному символу ('\0').Кроме этой особенности, можно отметить следующие специфические особенности строк:строка не может содержать внутри себя символ с кодом 0,в языке Си не предусмотрено ограничений на длину строки,длина строки не содержится в строке (в отличие от других языковпрограммирования, где есть понятие строки переменной длины).Определение строки оформляетсясоответствующего типа, например:какопределениесимвольногомассиваchar s[N];// строка из N символовМаксимальное количество значащих символов такой строки равно N - 1 , посколькув строке всегда должен присутствовать символ '\0'.При определении строки по аналогии с массивами можно задать ееинициализацию.
Для инициализации строк используются строковые константы(строковые литералы) вида "<последовательность символов>". Такая константаимеет типchar const * и в своем внутреннем представлении заканчиваетсясимволом '\0' , поэтому фактическая длина константной строки в памяти всегда на 1больше, чем количество символов, указанных в двойных кавычках.
Например,инициализация:char er[10]= "error";// er[0]='e', …, er[4] = 'r', er[5]= '\0'определяет строку из 10 символов, первые пять из которых получат указанные встроковой константе значения, а шестой будет содержать символ с кодом 0. Как и вслучае символьных констант, префикс L позволяет задать строковую константу вкодировке Unicode, например, L"unicode string".Для ввода/вывода строк можно использовать функции scanf и printf соспецификатором формата %s .
Например:char str[10];scanf ("%s", str);// ввод строкиФункция scanf последовательно считывает в строку str символы вводимой строки(предварительно пропустив пробелы, символы перевода на следующую строку и т.п.) и30автоматически добавляет в конец строки символ '\0'. Ввод выполняется до первогосимвола пробел, символа перевода на следующую строку и т.п. (полный перечень такихсимволов см. в описании функции scanf [1]).
Размер массива str должен бытьдостаточным для размещения в нем вводимой строки и добавленного к ней символа'\0'. Существенным недостатком данного варианта функции scanf, является то, чтоздесь никак не контролируется количество вводимых символов, что может представлятьугрозу для работы программы. Поэтому при использовании функции scanfрекомендуется задавать ограничение на размер вводимой строки:char str[10];scanf ("%9s", str);//ввод <= 9 символов с добавлением '\0'// в конец строкиВывод строки:char str[10];printf ("%s", str);При выводе строки на печать выводятся все значащие символы строки до символа'\0'.6.2.2.
Работа со строкамиПри работе со строками используется стандартная библиотека функций.Подключить ее можно директивой препроцессора:#include <string.h>В качестве примеров работы со строками рассмотрим реализацию некоторых функцийиз этой библиотеки. При обработке строк удобно использовать указатели, что и будетпродемонстрировано в приведенных ниже примерах.Задача 1. Реализовать функцию, которая возвращает длину (количество значащихсимволов) строки cs, с прототипом:size_t strlen (const char *cs);где size_t – это тип, который используется в стандартной библиотеке Си для заданияразмеров объекта и является синонимом (typedef) некоторого целого типа (часто –unsigned long).Для решения задачи воспользуемся двумя указателями, один из которых (cs) будетуказывать на начало строки, а другой (tmp) будем перемещать по строке до первогосимвола с кодом 0.
Разность указателей и даст результат функции.size_tstrlen (const char *cs){char *tmp = cs;while (*tmp) // пока очередной символ ≠ '\0'tmp++;return tmp – cs;}31Задача 2. Реализовать функцию с прототипом:char *strcpy (char *dst, const char *src);для копирования строки src (включая '\0') в строку dst . Функция возвращаетуказатель на первый символ строки dst.char *strcpy (char *dst, const char *src){char *tmp = dst;while (*dst++ = *src++);return tmp;}Основной интерес в предложенной реализации представляет выражение в условиицикла. Оно вычисляется следующим образом: берется символ по указателю src (послечего указатель src передвигается на следующий символ копируемой строки) ипомещается по указателю dst, после чего указатель dst аналогично передвигается наследующий символ строки. Значением выражения присваивания является только чтоскопированный символ, который сравнивается с '\0' для контроля завершения цикла.Таким образом, в результате выполнения цикла в строку dst копируются все символыисходной строки src, включая завершающий символ '\0'.
Обратите внимание напорядок выполнения операций при вычислении выражения *src++ . Операции * и ++имеют одинаковый приоритет и выполняются справа налево. Однако постфикснаяоперация ++ не изменяет указатель src, пока по нему не получено значение. В итогезначением данного выражения является символ, на который указывал указатель src досвоего инкрементирования.никак не контролируетЗаметим, что библиотечная функцияstrcpyвозможность переполнения массива. Контроль переполнения массива в языке Си обязаносуществлять сам программист.
В связи с этим рекомендуется использовать болеенадежный и безопасный вариант функции копирования (strncpy) с прототипом:char *strncpy (char *dst, const char *src, size_t n);в котором предусмотрена возможность ограничить размер копируемой строки.Параметр n задает максимальное число копируемых символов. Данная функция копируетне более n символов строки src в строку dst, при этом результирующая строкадополняется символами '\0', если в строке src меньше n символов. Функциявозвращает указатель на первый символ результирующей строки (dst).
Обратитевнимание, что если длина (количество значащих символов) исходной строки src большеили равна n, то копируются первые n символов строки и символ '\0' при этом недобавляется.Данный «безопасный» вариант функции копирования (strncpy) по сравнению с«опасным» вариантом (strcpy) при своей работе выполняет дополнительные операции –сравнение количества скопированных символов с параметром n, что приводит кзначительным дополнительным затратам, поскольку сама функция копирования оченьпроста. Поэтому нужно делать осознанный выбор между опасным, но более32производительным вариантом и безопасным, но более медленным. Например,использовать безопасный вариант strncpy только при начальной проверке вводапользователя на корректность, а далее проверку выхода за границы буфера выполнятьсамостоятельно пред вызовом функции strcpy.Приведем краткое описание еще нескольких функций стандартной библиотеки дляработы со строками.1) char *strcat (char *s, const char *ct);Функция приписывает строку ct в конец строки s; возвращается указатель на первыйсимвол строки s.Так же, как для функции копирования, существует более надежный вариант этойфункции с прототипом:char *strncat (char *s, const char *ct, size_t n);, который ограничивает (<= n) количество приписываемых символов.
Именно этотвариант и рекомендуется использовать для конкатенации строк.2) int strcmp(const char *cs, const char *ct);Функция сравнивает в лексикографическом порядке строку cs со строкой ct. Еслистрока cs меньше строки ct, возвращается значение < 0, если строка cs больше строкиct, возвращается значение > 0, в случае равенства строк возвращается значение 0.Обратите внимание, что для сравнения строк нельзя использовать операции ==,!= и т.п., поскольку при этом происходит сравнение указателей (адресов) на началосоответствующих строк, а не самих строк.3) char *strchr (const char *cs, char c);Функция возвращает указатель на первое вхождение символа c в строку cs или NULL,если такого не оказалось.4) char *strrchr (const char *cs, char c);Функция возвращает указатель на последнее вхождение символа c в строку cs илиNULL, если такого не оказалось.6.3.