#arrays #c
#массивы #c
Вопрос:
Я очень новичок в программировании (с августа), и рекурсия — моя ахиллесова пята. Вопрос заключается в следующем: напишите рекурсивную функцию printArray()
, которая принимает массив и размер массива в качестве аргументов, печатает массив и ничего не возвращает. Функция должна прекратить обработку и вернуться, когда получит массив нулевого размера.
Значит, сама по себе функция была бы чем-то вроде этого?:
void printArray(int arr[], int SIZE) {
int counter = 0;
if (SIZE == 0) {
return -1;
}
else if (SIZE > 0) {
printf("%d", arr[counter]);
counter ;
printArray(arr, SIZE - 1);
}
puts("");
}
Я, честно говоря, хватаюсь за соломинку, так что извините за беспокойство, которое я могу вызвать, поскольку я просматриваю бесчисленное количество кодов и пытаюсь собрать некоторые из них воедино и посмотреть, может ли это мне как-то помочь.
И при реализации его в main()
, должен ли я инициализировать дополнительные переменные? В основном это новый массив, поскольку все, что я помещаю arr[]
в параметр функции, выходит за рамки.
Комментарии:
1. Вы говорите «ничего не возвращать», но затем имеете
return -1
?2. «Значит, сама функция будет примерно такой?» — Да …, что- то вроде этого .
Ответ №1:
Рекурсивным функциям требуется немного подумать, чтобы отследить путь выполнения программы, поскольку рекурсивные вызовы «заводятся», а затем «разматываются» после прерывания рекурсии и завершения каждого рекурсивного вызова функции. Например, возьмем простой случай:
void prnarray (int *arr, int nelem)
{
if (--nelem > 0) /* wind-in (twice) until nelem == 0 */
prnarray (arr, nelem);
printf ("%dn", arr[nelem]); /* unwind outputting elements */
}
(где nelem
— количество элементов в массиве, технически не его «размер» [если это не массив char
])
Проследите, что произойдет, если эта функция была вызвана с:
int main (void) {
int arr[] = { 1, 2, 3 },
nelem = sizeof arr/sizeof *arr;
prnarray (arr, nelem);
}
Самый простой способ — просто создать таблицу со значением nelem
. Например:
Извлечение
nelem == 3
:
первоначальный вызов из main()
prnarray (arr, nelem);
затем при первом вызове функции --nelem
уменьшает значение nelem
на 1
перед вычислением if()
.
nelem == 2
:
после if()
инструкции путь выполнения:
if (--nelem > 0) /* wind-in (twice) until nelem == 0 */
prnarray (arr, nelem);
nelem == 1
:
затем в следующем вызове после --nelem
, nelem == 1
:
if (--nelem > 0) /* wind-in (twice) until nelem == 0 */
prnarray (arr, nelem);
nelem == 0
затем при следующем вызове, последнем рекурсивном вызове, выполняется базовый вариант, потому что после --nelem
, nelem == 0
поэтому условие теста не выполняется, и путь выполнения продолжается с:
printf ("%dn", arr[nelem]); /* unwind outputting elements */
(здесь печатается первый элемент ‘1’)
Разматывание
Что теперь происходит?? Мы достигли конца функции??
Выполнение начнется после вызова функции, которая приведет к этой точке. Где это?Вызов функции, который приводит к этой точке, является рекурсивным вызовом prnarray()
, который приводит к тому, что мы находимся в теле этой функции.
(под капотом каждый вызов функции сохраняет адрес базового указателя в стеке функций, поэтому, когда выполнение функции завершено, она знает, где возобновить выполнение в вызывающей функции.)
nelem == 1
Поэтому, когда выполнение функции where nelem == 0
заканчивается, мы возвращаемся к тому, на чем остановились в вызове функции where nelem == 1
— который возвращается из предыдущего вызова prnarray()
, если мы посмотрим на всю функцию where nelem == 1
( nelem == 2
при вводе функции), мы возвращаемся после предыдущего вызова на prnarray()
один уровень вверх в recusrion:
void prnarray (int *arr, int nelem)
{
if (--nelem > 0) /* wind-in (twice) until nelem == 0 */
<----- prnarray (arr, nelem);
|
-->printf ("%dn", arr[nelem]); /* unwind outputting elements */
}
(здесь печатается второй элемент со значением 2
)
Таким образом, после предыдущего prnarray()
развертывания в пути выполнения остается единственная команда printf()
, и печатается второй элемент 2
, и функция завершается и снова разворачивается с тем же результатом:
nelem == 2
( 3
при входе в функцию) путь выполнения — это printf()
функция
printf ("%dn", arr[nelem]); /* unwind outputting elements */
(здесь печатается третий и последний элемент со значением 3
)
nelem == 3
был исходный вызов функции из main()
, так что теперь развертывание завершено, и выполнение программы начинается main()
после вызова:
prnarray (arr, nelem);
и программа завершается….
Продумывание пути выполнения программы с рекурсивной функцией и создание таблицы — хороший способ освоиться с рекурсивными вызовами функций. (даже если они вас устраивают, когда вы добираетесь до функций, выполняющих два или более рекурсивных вызова в теле функции, вы сразу же вернетесь к созданию таблицы и отслеживанию пути выполнения). Ветви в пути выполнения программы с несколькими рекурсивными вызовами отдельных рекурсивных функций, по-видимому, будут расширяться с экспоненциальной сложностью.
С помощью этой информации вы теперь сможете настроить свою функцию и знать, где искать результат, который будет иметь место. Дайте мне знать, если у вас возникнут дополнительные вопросы.
Ответ №2:
В вашем решении
counter
является локальной для функции и не влияет на рекурсивный вызов, поэтому все время печатается только первый элемент массива.- при
SIZE
нулевом возврате вы возвращаете-1
ошибку компиляции.
Попробуйте передать адрес первого индекса массива примерно так, как показано ниже,
void printArray(int arr[], int SIZE)
{
if (SIZE > 0) {
printf("%d ", arr[0]);
printArray(amp;arr[1], SIZE - 1);
}
}
Ответ №3:
Вы могли бы перепроектировать ту же функцию, что и (обратите внимание на комментарии):
// Signature -- array size parameterized counter
void printArray(int arr[], int SIZE, int counter) {
if (SIZE == 0)
// Quitting from the function instead of returning to a void function
return;
// Will print arr[0] on first recursion
printf("%dn", arr[counter]);
counter ;
// Will re-execute and print counter (if it was 0, then 1, then 2, ...)
printArray(arr, SIZE - 1, counter);
}