ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 31.03.2021
Просмотров: 335
Скачиваний: 1
мы разбили программу на три файла:
-
файл проекта: func_palendrom.cpp
-
заголовочный файл palendrom.h
-
исполняемый файл palendrom.cpp
Файл проекта связываем с заголовочным файлом, а заголовочный файл связываем с исполняемым файлом, в таком случае файл проекта увидит функцию palindrom5() и сможет её запустить.
Передача указателей и массивов в качестве аргументов
До сих пор в приводимых здесь примерах функциям передавались значения простых переменных. Но возможны ситуации, когда в качестве аргументов необходимо использовать указатели и массивы. Рассмотрению особенностей передачи аргументов этого типа и посвящены следующие подразделы.
Вызов функций с указателями
В C++ разрешается передавать функции указатели. Для этого достаточно объявить параметр типа указатель. Рассмотрим пример.
// Передача функции указателя.
#include <iostream>
using namespace std;
void f (int *j);
int main()
{
int i;
int *p;
p = &i; // Указатель p теперь содержит адрес переменной i.
f(p);
cout << i; // Переменная i теперь содержит число 100.
return 0;
}
void f (int *j)
{
*j = 100; // Переменной, адресуемой указателем j, присваивается число 100.
}
Как видите, в этой программе функция f() принимает один параметр: указатель на целочисленное значение. В функции main() указателю р присваивается адрес переменной i. Затем из функции main() вызывается функция f(), а указатель р передается ей в качестве аргумента. После того как параметр-указатель j получит значение аргумента р, он (так же, как и р) будет указывать на переменную i, определенную в функции main(). Таким образом, при выполнении операции присваивания
*j = 100;
переменная i получает значение 100. Поэтому программа отобразит на экране число 100. В общем случае приведенная здесь функция f() присваивает число 100 переменной, адрес которой был передан этой функции в качестве аргумента.
В предыдущем примере необязательно было использовать переменную р. Вместо нее при вызове функции f() достаточно использовать переменную i, предварив ее оператором "&" (при этом, как вы знаете, генерируется адрес переменной i). После внесения оговоренного изменения предыдущая программа приобретает такой вид.
// Передача указателя функции -- исправленная версия.
#include <iostream>
using namespace std;
void f (int *j);
int main()
{
int i;
f(&i);
cout << i;
return 0;
}
void f (int * j)
{
*j = 100; // Переменной, адресуемой указателем j, присваивается число 100.
}
Передавая указатель функции, необходимо понимать следующее. При выполнении некоторой операции в функции, которая использует указатель, эта операция фактически выполняется над переменной, адресуемой этим указателем. Таким образом, такая функция может изменить значение объекта, адресуемого ее параметром.
Вызов функций с массивами
Если массив является аргументом функции, то необходимо понимать, что при вызове такой функции ей передается только адрес первого элемента массива, а не полная его копия. Это означает, что объявление параметра должно иметь тип, совместимый с типом аргумента. Вообще существует три способа объявить параметр, который принимает указатель на массив.
Во-первых, параметр можно объявить как массив, тип и размер которого совпадает с типом и размером массива, используемого при вызове функции. Этот вариант объявления параметра-массива продемонстрирован в следующем примере.
#include <iostream>
using namespace std;
void display(int num[10]);
int main()
{
int t[10], i;
for(i=0; i<10; ++i) t[i]=i;
display(t); // Передаем функции массив t
return 0;
}
// Функция выводит все элементы массива.
void display(int num[10])
{
int i;
for(i=0; i<10; i++) cout << num[i] <<' ';
}
Несмотря на то что параметр num объявлен здесь как целочисленный массив, состоящий из 10 элементов, С++-компилятор автоматически преобразует его в указатель на целочисленное значение. Необходимость этого преобразования объясняется тем, что никакой параметр в действительности не может принять массив целиком. А так как будет передан один лишь указатель на массив, то функция должна иметь параметр, способный принять этот указатель.
Второй способ объявления параметра-массива состоит в его представлении в виде безразмерного массива, как показано ниже.
void display(int num[])
{
int i;
for(i=0; i<10; i++) cout << num[i] << ' ';
}
Здесь параметр num объявляется как целочисленный массив неизвестного размера.
Целочисленный массив при таком способе объявления также автоматически преобразуется С++-компилятором в указатель на целочисленное значение.
Третий способ объявления параметра-массива. При передаче массива функции ее параметр можно объявить как указатель. Как раз этот вариант чаще всего используется профессиональными программистами. Вот пример:
void display(int *num)
{
int i;
for(i=0; i<10; i++) cout << num[i] << ' ';
}
Возможность такого объявления параметра (в данном случае num) объясняется тем, что любой указатель (подобно массиву) можно индексировать с помощью символов квадратных скобок ([]). Таким образом, все три способа объявления параметра-массива приводятся к одинаковому результату, который можно выразить одним словом: указатель.
Однако отдельный элемент массива, используемый в качестве аргумента, обрабатывается подобно обычной переменной. Например, рассмотренную выше программу можно было бы переписать, не используя передачу целого массива:
#include <iostream>
using namespace std;
void display(int num);
int main()
{
int t[10],i;
for(i=0; i<10; ++i) t[i]=i;
for(i=0; i<10; i++) display(t[i]);
return 0;
}
// Функция выводит одно число.
void display(int num)
{
cout << num << ' ';
}
Как видите, параметр, используемый функцией display(), имеет тип int. Здесь не важно, что эта функция вызывается с использованием элемента массива, поскольку ей передается только один его элемент.
Помните, что, если массив используется в качестве аргумента функции, то функции передается адрес этого массива. Это означает, что код функции может потенциально изменить реальное содержимое массива, используемого при вызове функции. Например, в следующей программе функция cube() преобразует значение каждого элемента массива в куб этого значения. При вызове функции cube() в качестве первого аргумента необходимо передать адрес массива значений, подлежащих преобразованию, а в качестве второго — его размер.
#include <iostream>
using namespace std;
void cube(int *n, int num);
int main()
{
int i, nums[10];
for(i=0; i<10; i++) nums[i] = i+1;
cout << "Исходное содержимое массива: ";
for(i=0; i<10; i++) cout << nums[i] << ' ';
cout << '\n';
cube(nums, 10); // Вычисляем кубы значений.
cout << "Измененное содержимое: ";
for(i=0; i<10; i++) cout << nums[i] << ' ';
return 0;
}
void cube(int *n, int num)
{
while(num) {
*n = *n * *n * *n;
num--;
n++;
}
}
Результаты выполнения этой программы таковы.
Исходное содержимое массива: 12345678910
Измененное содержимое: 1 8 27 64 125 216 343 512 729 1000
Как видите, после обращения к функции cube() содержимое массива nums изменилось: каждый элемент стал равным кубу исходного значения. Другими словами, элементы массива nums были модифицированы инструкциями, составляющими тело функции cube(), поскольку ее параметр n указывает на массив nums.
Передача функциям строк
Как вы уже знаете, строки в C++ — это обычные символьные массивы, которые завершаются нулевым символом. Таким образом, при передаче функции строки реально передается только указатель (типа char*) на начало этой строки. Рассмотрим, например, следующую программу. В ней определяется функция stringupper(), которая преобразует строку символов в ее прописной эквивалент.
// Передача функции строки.
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
void stringupper(char *str);
int main()
{
char str[80];
strcpy(str, "Мне нравится C++");
stringupper(str);
cout << str; // Отображаем строку с использованием прописного написания символов.
return 0;
}
void stringupper(char *str)
{
while(*str) {
*str = toupper(*str); // Получаем прописной эквивалент одного символа.
str++; // Переходим к следующему символу.
}
}
Результаты выполнения этой программы таковы.
МНЕ НРАВИТСЯ C++
Обратите внимание на то, что параметр str функции stringupper() объявляется с использованием типа char*. Это позволяет получить указатель на символьный массив, который содержит строку.
Рассмотрим еще один пример передачи строки функции. Как вы узнали в главе 5, стандартная библиотечная функция strlen() возвращает длину строки. В следующей программе показан один из возможных вариантов реализации этой функции.
// Одна из версий функции strlen().
#include <iostream>
using namespace std;
int mystrlen(char *str);
int main()
{
cout << "Длина строки ПРИВЕТ ВСЕМ равна: ";
cout << mystrlen("ПРИВЕТ ВСЕМ");
return 0;
}
// Нестандартная реализация функции strlen().
int mystrlen(char *str)
{
int i;
for(i=0; str[i]; i++); // Находим конец строки.
return i;
}
Вот как выглядят результаты выполнения этой программы.
Длина строки ПРИВЕТ ВСЕМ равна: 11
В качестве упражнения вам стоило бы попытаться самостоятельно реализовать другие строковые функции, например strcpy() или strcat(). Этот тест позволит узнать, насколько хорошо вы освоили такие элементы языка C++, как массивы, строки и указатели.
Аргументы функции main(): argc и argv
Аргумент командной строки представляет собой информацию, задаваемую в командной строке после имени программы.
Иногда возникает необходимость передать информацию программе при ее запуске. Как правило, это реализуется путем передачи аргументов командной строки функции main(). Аргумент командной строки представляет собой информацию, указываемую в команде (командной строке), предназначенной для выполнения операционной системой, после имени программы. Например, С++-программы можно компилировать путем выполнения следующей команды,
cl prog_name
Здесь элемент prog_name — имя программы, которую мы хотим скомпилировать. Имя программы передается С++-компилятору в качестве аргумента командной строки.
В C++ для функции main() определено два встроенных, но необязательных параметра, argc и argv, которые получают свои значения от аргументов командной строки. В конкретной операционной среде могут поддерживаться и другие аргументы (такую информацию необходимо уточнить по документации, прилагаемой к вашему компилятору). Рассмотрим параметры argc и argv более подробно.
На заметку. Формально для имен параметров командной строки можно выбирать любые идентификаторы, однако имена argc и argv используются по соглашению уже в течение нескольких лет, и поэтому имеет смысл не прибегать к другим идентификаторам, чтобы любой программист, которому придется разбираться в вашей программе, смог быстро идентифицировать их как параметры командной строки.
Параметр argc имеет целочисленный тип и предназначен для хранения количества аргументов командной строки. Его значение всегда не меньше единицы, поскольку имя программы также является одним из учитываемых аргументов. Параметр argv представляет собой указатель на массив символьных указателей. Каждый указатель в массиве argv ссылается на строку, содержащую аргумент командной строки. Элемент argv[0] указывает на имя программы; элемент argv[1] — на первый аргумент, элемент argv[2] — на второй и т.д. Все аргументы командной строки передаются программе как строки, поэтому числовые аргументы необходимо преобразовать в программе в соответствующий внутренний формат.
Важно правильно объявить параметр argv. Обычно это делается так.
char *argv[];
Доступ к отдельным аргументам командной строки можно получить путем индексации массива argv. Как это сделать, показано в следующей программе. При ее выполнении на экран выводится приветствие ("Привет" ), а за ним — ваше имя, которое должно быть первым аргументом командной строки.
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
if(argc!=2) {
cout << "Вы забыли ввести свое имя.\n";
return 1;
}
cout << "Привет, " << argv[1] << '\n';
return 0;
}
Предположим, что вас зовут Том и что вы назвали эту программу именем name. Тогда, если запустить эту программу, введя команду name Том, результат ее работы должен выглядеть так: Привет, Том. Например, вы работаете с диском А, и в ответ на приглашение на ввод команды должны ввести упомянутую выше команду и получить следующий результат.
A>name Том
Привет, Том
А>
Чтобы получить доступ к отдельному символу в одном из аргументов командной строки, при обращении к массиву argv добавьте второй индекс. Например, при выполнении приведенной ниже программы посимвольно отображаются все аргументы, с которыми она была вызвана.
/* Эта программа посимвольно выводит все аргументы командной строки, с которыми она была вызвана.
*/
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int t, i;
for(t=0; t<argc; ++t) {
i = 0;
while(argv[t][i]) {
cout << argv[t][i];
++i;
}
cout << ' ';
}
return 0;
}
Нетрудно догадаться, что первый индекс массива argv позволяет получить доступ к соответствующему аргументу командной строки, а второй — к конкретному символу этого строкового аргумента.
Обычно аргументы argc и argv используются для ввода в программу начальных параметров, исходных значений, имен файлов или вариантов (режимов) работы программы. В C++ можно ввести столько аргументов командной строки, сколько допускает операционная система. Использование аргументов командной строки придает программе профессиональный вид и позволяет использовать ее в командном файле (исполняемом текстовом файле, содержащем одну или несколько команд).
Передача числовых аргументов командной строки
Как упоминалось выше, при передаче программе числовых данных в качестве аргументов командной строки эти данные принимаются в строковой форме. В программе должно быть предусмотрено их преобразование в соответствующий внутренний формат с помощью одной из стандартных библиотечных функций, поддерживаемых C++. Например, при выполнении следующей программы выводится сумма двух чисел, которые указываются в командной строке после имени программы. Для преобразования аргументов командной строки во внутреннее представление здесь используется стандартная библиотечная функция atof(). Она преобразует число из строкового формата в значение типа double.
/* Эта программа отображает сумму двух числовых аргументов командной строки.
*/
#include <iostream>
#include <cstdlib>
using namespace std
int main(int argc, char *argv[])
{
double a, b;
if(argc!=3) {
cout << "Использование: add число число\n";
return 1;
}
a = atof(argv[1]);
b = atof(argv[2]);
cout << a + b;
return 0;
}
Чтобы сложить два числа, используйте командную строку такого вида (предполагая, что эта программа имеет имя add).
C>add 100.2 231
Преобразование числовых строк в числа
Стандартная библиотека C++ включает несколько функций, которые позволяют преобразовать строковое представление числа в его внутренний формат. Для этого используются такие функции, как atoi(), atol() и atof(). Они преобразуют строку в целочисленное значение (типа int), длинное целое (типа long) и значение с плавающей точкой (типа double) соответственно. Использование этих функций (для их вызова необходимо включить в программу заголовочный файл <cstdlib>) демонстрируется в следующей программе.
// Демонстрация использования функций atoi(), atol() и atof().
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int i;
long j;
double k;
i = atoi ("100");
j = atol("100000");
k = atof("-0.123");
cout << i << ' ' << j << ' ' << k;
cout << ' \n';
return 0;
}
Результаты выполнения этой программы таковы.
100 100000 -0.123
Функции преобразования строк полезны не только при передаче числовых данных программе через аргументы командной строки, но и в ряде других ситуаций.