76. Передача данных через указатели
Из рассмотренных выше примеров может создаться впечатление, что функции могут возвращать только одно значение – через свое имя. Однако это было бы очень серьезным ограничением полезности функций. Очень часто (в подавляющем большинстве случаев) требуется, чтобы функции возвращали более одного, сформированного внутри функции, значения.
Решение этой проблемы: необходимо заставить функцию обрабатывать не копию аргумента, а само значение аргумента.
Для этого можно использовать передачу данных с помощью указателей.
Рассмотрим пример: необходимо разработать функцию, возвращающую результат деления и остаток от деления двух целых чисел.
int Div (int N1, int N2, int *Ost) // int *Ost – параметр-указатель
{
*Ost = N1 % N2; // *Ost – разыменование параметра-указателя
return N1 / N2;
}
int main()
{
int I = 10, J = 3, R, O;
R = Div (I, J, &O); // &O – адрес аргумента O
cout << I << “ / ” << J << “ = ” << R << “. Остаток равен “ << O << endl;
return 0;
}
Функция Div находит результат и остаток от деления параметра N1 на N2. Результат деления возвращается через имя функции, а остаток через параметр Ost.
Для того чтобы обеспечить возвращение вычисленного внутри функции остатка, соответствующий параметр функции определен как указатель (int *Ost). При вызове функции в качестве аргумента для этого параметра был использован адрес переменной &O, а не само значение переменной O. При вычислении остатка внутри функции выполняется разыменование параметра Ost (*Ost - обращение по адресу, хранящемуся в параметре Ost), и вычисленный остаток записывается по этому адресу (то есть в переменную O). Таким образом, значение переменной O изменяется.
В принципе здесь также используется передача данных по значению. Но в качестве значения используется адрес аргумента, а не само значение аргумента. И далее в функции осуществляется работа со значением аргумента путем обращения к нему через его адрес.
Таким образом, для использования передачи данных с помощью указателей необходимо обязательно выполнить три следующих пункта:
1. Соответствующий параметр в заголовке функции необходимо определить как указатель на тип данных аргумента.
2. При вызове функции на месте параметров-указателей необходимо использовать адрес аргумента, а не сам аргумент.
3. При обращении внутри функции к значению аргумента через параметр-указатель необходимо осуществить разыменование этого указателя.
Несколько проще обстоит дело с передачей массивов, так как переменные типа массив сами являются указателями на первый элемент массива. В связи с этим отпадает необходимость в выполнении пунктов 2 и 3 из перечисленных выше. Рассмотрим пример:
void ReadArr ( int *P, int n)
{
for (int I = 0; I < n; ++I)
cin >> P[I];
}
void WriteArr ( int Arr[], int n)
{
for (int I = 0; I < n; ++I)
cout << Arr[I] << “ “;
cout << endl;
}
int main()
{
const n = 10;
int A[n];
ReadArr (A, n);
WriteArr (A, n);
return 0;
}
В первой функции параметр для передачи массива определен как указатель на тип int, то есть через этот параметр может быть передан адрес первого элемента массива.
Во второй функции параметр для передачи массива определен как массив из элементов типа int, но это одновременно и указатель на первый элемент массива.
Внутри первой функции при обращении к очередному элементу массива никакого разыменования указателя не требуется, так как указатели могут индексироваться непосредственно.
Во второй функции при обращении к очередному элементу массива также не требуется разыменовывать параметр Arr – обращение к ним осуществляется естественным для массива способом – с помощью индексации элементов.
Кода осуществляется вызов этих функций, определять адрес аргумента для параметра–массива необходимости нет, так как переменная A сама является адресом первого элемента массива.
Таким образом, оба эти способа передачи массивов являются эквивалентными и оба они допускают передачу измененных внутри функции значений элементов массива в вызывающую часть программы.
Поскольку строки символов являются массивами, их передача в функции осуществляется так же, как и обычных массивов. Например:
void StringProc(char * S, int L)
или
void StringProc(char S[], int L)
Этот способ передачи данных часто называют передачей данных по адресу.
- 2. Структура и основные элементы программы
- 3.Общее понятие типов данных
- 4. Переменные и константы
- 5.Основные типы данных
- 6. Спецификаторы типов данных
- 7. Определение переменных и констант в программе
- 8. Инициализация переменных различных типов
- 9.Целочисленные типы данных
- 10. Вещественные типы данных
- 11. Особенности представления вещественных типов данных
- 12.Логический тип данных
- 13. Символьный тип данных
- 14. Управляющие последовательности
- 15. Операции и выражения
- 16. Операция присваивания, составные операции присваивания
- 17. Понятие l-значения
- 18. Преобразование типов данных
- 19. Арифметические операции
- 20. Операции инкремента и декремента, их разновидности
- 21. Операции отношения
- 22. Логические операции
- 23. Побитовые операции сдвига
- 24. Побитовые логические операции
- 25. Примеры применения побитовых операций
- 26. Условная операция и ее использование
- 27. Определение объема памяти, необходимого для размещения объектов
- 28. Понятие приоритета операций и его влияние на результаты вычислений
- 31.Флаги форматирования потоков ввода-вывода
- 32. Форматирование ввода-вывода с помощью манипуляторов
- 33.Форматирование ввода-вывода с помощью функций потоков ввода-вывода
- 34. Управление шириной поля вывода и выравниванием данных при выводе
- 35. Управление форматом вывода вещественных значений
- 36. Основные понятия структурного программирования
- 37. Базовый набор управляющих структур
- 39.Условная инструкция (if)
- 40. Инструкция множественного выбора (switch)
- 42. Цикл с постусловием (do while)
- 43. Итерационный цикл (for)
- 46. Инструкция перехода goto
- 47. Понятие рекуррентных вычислений, примеры
- 48. Понятие инварианта цикла
- 49. Понятие и определение массива
- 52. Ввод элементов массивов с клавиатуры
- 53. Декларативная и программная инициализация массивов
- 54. Копирование массивов
- 55. Нахождение минимальных и максимальных значений в массивах
- 56. Сдвиг элементов массивов
- 57. Перестановка элементов в массивах
- 58. Поиск данных в массивах
- 59. Сортировка данных в массивах
- 60. Вычисление сумм и произведений элементов массивов
- 61. Представление текстовых строк в виде массива символов
- 62. Ввод-вывод символьных строк
- 63. Определение фактической длины строки
- 64. Копирование символьных строк
- 65. Основные функции обработки строк библиотеки cstring
- 66. Массивы текстовых строк (двумерные массивы символов)
- 67. Указатели Понятие указателя
- Работа с указателями
- 68. Арифметика указателей
- 69. Индексирование указателей
- 70. Ссылки
- 71. Определение функции
- 72. Инструкция return
- 73. Завершение работы функции
- 74. Механизмы передачи данных через параметры функций
- 75. Передача данных по значению
- 76. Передача данных через указатели
- 77. Передача данных по ссылке
- 78. Параметры по умолчанию
- 79. Функции с переменным числом параметров
- 80. Inline функции
- 81. Перегрузка функций
- 82. Рекурсия
- 83. Прототипы функций