Передача строки в функцию
Просматривая статьи о функциях на разных сайтах для новичков в С++, прихожу к выводу, что, зачастую, в примерах показано, как передавать функциям, в качестве параметров, числовые типы данных ( int , float , double и т.д.). Так появилась идея написать данную статью, где на практике хочу показать, как передать строку (она же — массив символов) в функцию в виде параметра. И просто замечательно, что в С++ таких способов несколько. Вы можете выбрать тот, который вам просто понравится или который больше подойдет для решения поставленной перед вами задачи.
Способы передачи строки в функцию хочу показать на одном примере. Чтобы лучше освоить материал и взять максимум пользы от прочитанного, открывайте свою среду разработки и переписывайте код по мере прочтения. Практика – лучший способ что-то понять и запомнить. Под примером будут расположены подробные комментарии и разъяснения по данному коду.
Задача всех наших созданных функций – отобразить на экране строки, которые переданы им, как параметры. Пойдем по порядку:
1) первый способ — функция void showText1 (char str[]) принимает строку, как массив — строка 4 . П ри определении функции, в круглых скобках надо вписать тип массива (строки) char , имя строки и квадратные скобки [] . Обратите внимание, что нам не надо указывать размерность массива (количество символов в строке). С помощью символа ‘\0′, который автоматически добавляется в конец любой строки , функция сама найдет последний элемент массива и прекратит вывод элементов на экран.
2) второй способ, передача строки в функцию при помощи указателя, самый распространенный вариант — строка 9. При определении функции, перед именем строки ставим оператор * — void showText2 (char *str) .
3) ну и третий способ, передача в функцию строки по адресу — строка 14. В нашем примере это функция void showText3 (char (&str)[150]) . Тут следует быть внимательным, т.к. необходимо указывать точный размер строки. Без этого компилятор выдаст ошибку (Мы проверяли :)). А так же важно взять в круглые скобки оператор & с именем строки — (&str) . В строке 38 нашего кода, вы можете видеть, что строка char str3[150] содержит явно меньше символов. Остальным, не инициализированным, будет присвоено значение ‘\0’ .
Думаю, строки 23-25 говорят сами за себя и комментировать не стоит. Иногда, так удобно сделать, не объявляя и не определяя строку заранее.
При вызове функций все просто – надо лишь внести название необходимой строки в круглые скобки. Строки 29, 34, 39.
Можно ввести строку в круглых скобках при вызове функции:
str1 — передаем, как массив в функцию void showText1 (char str[]);
str2 — передаем, в функцию void showText2 (char *str); используя указатель.
str3 — передаем, в функцию void showText3 (char &str[]);
Тут используем адрес строки (адрес первого элемента символьного массива)
А вот еще один пример, который покажет насколько удобно работать с указателем в функциях. В нем функция примет, в качестве параметра, указатель на строку символов, с помощью указателя пройдет по каждой ячейке памяти строки и изменит числовые символы на знак
или на букву O . В результате строка, содержащая числовые символы 1234123412341234 и т.д., с легкостью превратится в “новогоднюю гирлянду”. В этом коде указатель покажет себя, как альтернатива управляющей переменной в цикле while :
Смотрите, как интересно получается: как мы знаем, указатель указывает на адрес первой ячейки памяти строки, т.е. в нашем случае на str[0] . Значит, используя операцию разыменовывания указателя * , мы можем посмотреть, какой символ в этой ячейке хранится и, если надо, заменить его на другой — строки 6, 8, 9. Плюс, мы можем использовать указатель на строку, вместо управляющей переменной в нашем цикле while . Для этого, на каждой итерации цикла, инкрементируем указатель str++ — строка 11. Таким образом, указатель будет указывать уже на очередную ячейку памяти нашей строки. Так будет происходить до тех пор, пока указатель не перейдет на ячейку с символом ‘\0’ . Тут цикл while прекратит работу.
Результат — наша «новогодняя гирлянда» 🙂
Исходная строка: 12341234123412341234123
Каким способом передать строку в функцию — определяйтесь сами. Если у вас остались вопросы по теме, задавайте их нам в комментариях к этой статье. Мы вам обязательно ответим и поможем разобраться.
C++. Функции. Часть 2. Функции и массивы. Передача одномерного и многомерного массива в функцию. Передача структуры и класса в функцию
Функции. Часть 2. Функции и массивы. Передача одномерного и многомерного массива в функцию. Передача структуры и класса в функцию
Содержание
- 1. Пример определения функции, получающей массив целых чисел
- 2. Пример передачи строки символов в функцию
- 3. Как передать массив строк в функцию? Пример
- 4. Пример передачи двумерного массива как параметра функции
- 5. Пример передачи в функцию трехмерного массива чисел
- 6. Как передать структуру в функцию? Пример
- 7. Пример передачи в функцию управляемого указателя на структуру ссылочного типа ( ref )
- 8. Как в качестве параметра функции передать объект класса?
- Связанные темы
Поиск на других ресурсах:
1. Пример определения функции, получающей массив целых чисел
Для передачи массива чисел в функцию, нужно передать указатель на этот массив чисел.
Указателем на массив чисел есть:
- имя массива;
- адреса первого элемента массива.
Пример. Пусть нужно описать функцию SumArrayInts() , которая получает массив из целых чисел и находит сумму элементов этого массива. Функция получает 2 параметра:
- массив целых чисел;
- число элементов в массиве.
Способ 1. Передача массива как int A[] .
Способ 2. Передача массива как int *A .
Вызов функции SumArrayInts() из другого программного кода.
Следует заметить, что при такой передаче массива в функцию, элементы массива можно изменять в теле функции.
2. Пример передачи строки символов в функцию
Строка символов есть массивом элементов типа char . Поэтому, передача строки символов в функцию в качестве параметра выполняется точно так же, как и в случае с числами (п. 1).
Строку символов можно передавать в функцию двумя способами:
- как char* ;
- как char[] .
Пример. Функция, которая возвращает количество символов ‘+‘ (плюс) в строке. Признаком конца строки есть символ ‘\0’ . Поэтому не нужно передавать в функцию длину строки.
Способ 1. Определение функции GetNPlus() . Передача строки как char * .
Заголовок вышеприведенной функции можно было также определить следующим образом:
Способ 2. Определение функции GetNPlus2() . Использование индексов для доступа к символам строки.
Вызов функции GetNPlus2() из другого программного кода.
3. Как передать массив строк в функцию? Пример
Пример. Функция, которая получает массив строк и сортирует его методом вставки. Массив строк передается первым параметром. Вторым параметром передается количество строк.
В вышеприведенной функции использована функция strcmp() . Эта функция сравнивает 2 строки s1 и s2 в лексикографическом порядке:
и возвращает значение
- >0 , если строка s1 следует после строки s2 в лексикографическом порядке;
- =0 , если строки равны между собой;
- <0 , если строка s1 следует перед строкой s2 в лексикографическом порядке.
Вызов функции из другого программного кода:
4. Пример передачи двумерного массива как параметра функции
В данном примере описана функция, которая находит сумму элементов двумерного массива. Функция получает двумерный массив вещественных чисел в качестве параметра.
Вызов функции из программного кода. В функцию передается двумерный массив с именем M размером 2×3.
5. Пример передачи в функцию трехмерного массива чисел
В данном примере описывается функция Sum3() , которая получает входным параметром трехмерный массив целых чисел. Размер массива 2×3×4. Функция возвращает сумму элементов массива.
Вызов функции из другого программного кода
6. Как передать структуру в функцию? Пример
В качестве параметра структуру можно передавать в функцию двумя способами:
- по значению;
- по адресу;
- по ссылке (не используется в среде CLR ).
Более подробно о способах передачи параметров в функцию описывается здесь .
При передаче структуры по значению делается копия в стеке всех полей структурной переменной.
При передаче структуры по адресу передается только адрес структуры в памяти (указатель на структуру). Этот способ есть более эффективным, если для полей структуры нужно выделять много памяти (размер указателя может быть намного меньше размера структурной переменной).
Указатель на структуру, которая передается в функцию может быть двух типов:
- неуправляемый указатель ( * );
- управляемый указатель ( ^ ). В этом случае структура должна объявляться с ключевым словом ref ( см. п. 7 ).
Пример. Передача структурной переменной (объекта) по значению и по адресу (случай неуправляемого указателя * ).
Пусть за пределами класса (или в другом модуле) задана структура, которая описывает точку на координатной плоскости:
Пусть заданы 2 функции, которые определяют, равны ли точки между собой:
- функция Equals() , которая в качестве параметров получает 2 структурные переменные типа MyPoint (передача по значению);
- функция EqualsP() , которая получает 2 указателя на структурные переменные типа MyPoint (передача по адресу).
Тогда вызов функций Equals() и EqualsP() можно осуществить из другого программного кода приблизительно следующим образом:
7. Пример передачи в функцию управляемого указателя на структуру ссылочного типа ( ref )
В данном примере продемонстрирована передача в функцию управляемого ( ^ ) указателя на структуру. Функция EqualsPRef() получает два управляемых ( ^ ) указателя на структуру типа MyPoint . Функция определяет равенство полей структур, на которые указывают указатели.
Структура MyPoint имеет следующее описание:
Определение (реализация) функции EqualsPRef() :
Вызов функции EqualsPRef() из другого программного кода (например, обработчика события клика на кнопке):
8. Как в качестве параметра функции передать объект класса?
Пусть дан класс MyPointClass , описывающий координаты точки на плоскости. Класс определен в двух модулях:
- в модуле MyPointClass.h описывается описание функций и полей класса;
- в модуле MyPointClass.cpp описывается реализация методов и полей класса.
Текст модуля MyPointClass.h :
Текст модуля MyPointClass.cpp :
Пусть в главном модуле программы (например, класс формы) описана функция EqualsClass() , которая сравнивает поля класса MyPointClass . Функция получает два параметра – управляемые указатели на класс ( ^ ). Передать класс как параметр-значения не удастся, поскольку класс принадлежит к ссылочному типу. С классом нужно использовать управляемые указатели ( ^ ).
Более подробно об управляемых и неуправляемых указатели описывается здесь .
Вызов функции EqualsClass() из другого программного кода (например, из обработчика события):
Чтобы использовать методы класса, нужно предварительно подключить модуль MyPointClass.h :
9. Пример передачи структуры в функцию по ссылке (не поддерживается в среде CLR )
Структуру можно передавать в функцию по ссылке. Ниже дается программный код объявления структуры MyPoint , которая передается в функцию EqualsR() по ссылке для приложений типа Win32 . Для приложений, работающих в среде CLR такой способ передачи параметра не поддерживается.
Передача массивов и строк в функцию
Передача одномерных массивов и строк осуществляется с помощью указателей. Обратите внимание на то, что при вызове функции перед названием переменной не нужно добавлять оператор & , так как название переменной содержит адрес первого элемента массива. Пример передачи C-строки приведен в листинге 12.10.
Листинг 12.10. Передача C-строки в функцию
Объявление char *s эквивалентно объявлению char s[] . И в том и в другом случае объявляется указатель на тип char . Чаще используется первый способ. Обратите внимание на значения, возвращаемые оператором sizeof вне и внутри функции. Вне функции оператор возвращает размер всего символьного массива, в то время как внутри функции оператор sizeof возвращает только размер указателя. Это происходит потому что внутри функции переменная s является указателем, а не массивом. Поэтому, если внутри функции необходимо знать размер массива, то количество элементов (или размер в байтах) следует передавать в дополнительном параметре.
При передаче многомерного массива необходимо явным образом указывать все размеры (например, int a[2][4] ). Самый первый размер допускается не указывать (например, int a[][4] ). Пример передачи двумерного массива в функцию приведен в листинге 12.11.
Листинг 12.11. Передача двумерного массива
Такой способ передачи многомерного массива нельзя назвать универсальным, так как существует жесткая привязка к размеру. Одним из способов решения проблемы является создание дополнительного массива указателей. В этом случае в функцию передается адрес первого элемента массива указателей, а объявление параметра в функции выглядит так:
Пример передачи массива указателей приведен в листинге 12.12.
Листинг 12.12. Передача массива указателей
Однако и этот способ имеет недостаток, так как нужно создавать дополнительный массив указателей. Наиболее приемлемым способом является передача двумерного массива как одномерного. В этом случае в функцию передается адрес первого элемента массива, а в параметре объявляется указатель. Так как все элементы двумерного массива располагаются в памяти последовательно, зная количество элементов или размеры можно вычислить положение текущего элемента, используя адресную арифметику. Пример передачи двумерного массива как одномерного приведен в листинге 12.13.
Листинг 12.13. Передача двумерного массива как одномерного
Передача в функцию массива C-строк осуществляется так же как передача массива указателей. Чтобы в функцию не передавать количество элементов можно при инициализации массива C-строк последнему элементу присвоить нулевой указатель. Этот элемент будет служить ориентиром конца массива. В качестве примера выведем все строки внутри функции (листинг 12.14).
Листинг 12.14. Передача массива C-строк

Учебник C++ (Qt Creator и MinGW) в формате PDF
Помощь сайту
ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов
5.3. Массивы и строки как параметры функций Массивы в параметрах.
Массивы в параметрах. Если в качестве параметра функции используется обозначение массива, то на самом деле внутрь функции передается только адрес начала массива. Применяя массивы в качестве параметров для функций из главы 2, мы не отмечали этой особенности. Например, заголовок функции для вычисления скалярного произведения векторов выглядел так:
float ScaIar_Product(int n, float a[ ], float b[ ]).
Но заголовок той же функции можно записать и следующим образом:
float Scalar_Product(int n, float *a, float *b).
float b[ ]; и float *b;
совершенно равноправны в спецификациях параметров. Однако в первом случае роль имени b как указателя не так явственна. Во втором варианте все более очевидно — b явно определяется как указатель типа float *.
В теле функции Scalar_Product() из главы 2 обращение к элементам массивов-параметров выполнялось с помощью индексированных элементов a[i] и b[i]. Однако можно обращаться к элементам массивов, разыменовывая соответствующие значения адресов, т.е. используя выражения *(a+i) и *(i+b).
Так как массив всегда передается в функцию как указатель, то внутри функции можно изменять значения элементов массива — фактического параметра, определенного в вызывающей программе. Это возможно и при использовании индексирования, и при разыменовании указателей на элементы массива.
Для иллюстрации указанных возможностей рассмотрим функцию, возводящую в квадрат значения элементов одномерного массива, и вызывающую ее программу:

Чтобы еще раз обратить внимание на равноправие параметров в виде массива и указателя того же типа, отметим, что заголовок функции в нашей программе может быть и таким:
void quart (int n, float x [ ])
В теле функции разыменовано выражение, содержащее имя массива-параметра, т.е. вместо индексированной переменной x[i] используется *(x+i). Эту возможность мы уже неоднократно отмечали. Более интересная возможность состоит в том, что можно изменять внутри тела функции значение указателя на массив, т.е. в теле цикла записать, например, такой оператор:

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

В этом ошибочном случае «смещение» указателя х вдоль массива будет при каждой итерации цикла не на один элемент массива, а на 2, так как х изменяется и в левом, и в правом операндах операции присваивания.
Следует отметить, что имя массива внутри тела функции не воспринимается как константный (не допускающий изменений) указатель, однако такая возможность отсутствует в основной программе, где определен соответствующий массив (фактический параметр). Если в цикле основной программы вместо значения z[j] попытаться использовать в функции printf( ) выражение *z++, то получим сообщение об ошибке, т.е. следующие операторы не верны:

Сообщение об ошибке при компиляции выглядит так:

Подводя итоги, отметим, что, с одной стороны, имя массива является константным указателем со значением, равным адресу нулевого элемента массива. С другой стороны, имя массива, использованное в качестве параметра, играет в теле функции роль обычного (неконстантного) указателя, т.е. может использоваться в качестве леводопустимого выражения. Именно поэтому в спецификациях формальных параметров эквивалентны, как указано выше, например, такие формы:
double x[ ] и double *x
Строки как параметры функций. Строки в качестве фактических параметров могут быть специфицированы либо как одномерные массивы типа char [ ], либо как указатели типа char *. В обоих случаях с помощью параметра в функцию передается адрес начала символьного массива, содержащего строку. В отличие от обычных массивов для параметров-строк нет необходимости явно указывать их длину. Признак ‘\0’, размещаемый в конце каждой строки, позволяет всегда определить ее длину, точнее, позволяет перебирать символы строки и не выйти за ее пределы. Как примеры использования строк в качестве параметров функций рассмотрим несколько функций, решающих типовые задачи обработки строк. Аналоги большинства из приводимых ниже функций имеются в библиотеке стандартных функций компилятора (см. Приложение 3). Их прототипы и другие средства связи с этими функциями находятся в заголовочных файлах string.h и stdlib.h. Однако для целей темы, посвященной использованию строк в качестве параметров, удобно заглянуть «внутрь» таких функций.
Итак, в иллюстративных целях приведем определения функций для решения некоторых типовых задач обработки строк. Будем для полноты картины использовать различные способы задания строк-параметров.
Функция вычисления длины строки. Следующая ниже функция имеет самую старомодную и не рекомендуемую стандартом форму заголовка (в стандартной библиотеке ей соответствует функция strlen( ), см. Приложение 3):

В соответствии с ANSI-стандартом и со стандартом ISO заголовок должен иметь, например, такой вид:

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

Для формального параметра-указателя s внутри функции выделяется участок памяти, куда записывается значение фактического параметра. Так как s не константа, то значение этого указателя может изменяться. Именно поэтому допустимо выражение S++.
Функция инвертирования строки-аргумента с параметром-массивом (заголовок соответствует стандарту):

В определении функции invert( ) с помощью ключевого слова void указано, что функция не возвращает значения.
В качестве упражнения можно переписать функцию invert( ), заменив параметр-массив параметром-указателем типа char*.
При выполнении функции invert( ) строка — фактический параметр, например, «сироп» превратится в строку «порис». При этом символ ‘\0’ остается на своем месте в конце строки. Пример использования функции invert( ):

Результат выполнения программы:

Функция поиска в строке ближайшего слева вхождения другой строки (в стандартной библиотеке имеется подобная функция strstr( ), см. Приложение 3):

Функция index( ) возвращает номер позиции, начиная с которой СТ2 полностью совпадает с частью строки СТ1. Если строка СТ2 не входит в СТ1, то возвращается значение -1.
Пример обращения к функции index( ):

Результат выполнения программы:

В функции index( ) параметры специфицированы как указатели на тип char, а в теле функции обращение к символам строк выполняется с помощью индексированных переменных. Вместо параметров-указателей подставляют в качестве фактических параметров имена символьных массивов С1[ ], С2[ ], С3[ ]. Никакой неточности здесь нет: к массивам допустимы обе формы обращения — и с помощью индексированных переменных, и с использованием разыменования указателей.
Функция сравнения строк. Для сравнения двух строк можно написать следующую функцию (в стандартной библиотеке имеется близкая к этой функция strcmp( ), см. Приложение 3):

В теле функции обращение к элементам массивов-строк реализовано через разыменование указателей. Функция row( ) возвращает: значение -1, если длины строк-аргументов C1, C2 различны; 0 — если все символы строк совпадают. Если длины строк одинаковы, но символы не совпадают, то возвращается порядковый номер (слева) первых несовпадающих символов.
Особенность функции row( ) — спецификация параметров как массивов и обращение к элементам массивов внутри тела функции с помощью разыменования. При этом за счет операций С1++ и С2++ изменяются начальные «настройки» указателей на массивы. Одновременно в той же функции к тем же массивам-параметрам выполняется обращение и с помощью выражений *(C1+m1) и *(С2+m2), при вычислении которых значения С1 и С2 не меняются.
Функция соединения строк. Следующая функция позволяет «присоединить» к первой строке-аргументу вторую строку-аргумент (в стандартной библиотеке есть подобная функция strncat( ), см. Приложение 3):

Результат возвращается как значение первого аргумента С1. Второй аргумент С2 не изменяется. Обратите внимание на то, что при использовании функции conc( ) длина строки, заменяющей параметр С1, должна быть достаточной для приема результирующей строки.
Функция выделения подстроки. Для выделения из строки С1 фрагмента заданной длины (подстроки) можно предложить такую функцию:

Результат выполнения функции — строка С2[ ] из k символов, выделенных из строки С1[ ], начиная с символа, имеющего номер n. При неверном сочетании значений параметров возвращается пустая строка, использованная в качестве параметра С2.
Функция копирования содержимого строки. Так как в языке Си отсутствует оператор присваивания для строк, то полезно иметь специальную функцию, позволяющую «переносить» содержимое строки в другую строку (такая функция strcpy( ) есть в стандартной библиотеке, но она имеет другое возвращаемое значение):

Пример использования функции сору( ):

Результат выполнения тестовой программы:

Другой вариант функции копирования строки:

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

Так как ненулевое значение в выражении после while считается истинным, то явное сравнение с ‘\0’ необязательно и возможно следующее упрощение функции: