Как переменная char хранится в рекурсии? - PullRequest
0 голосов
/ 20 марта 2020
#include <stdio.h>
void reverseSentence();
int main() {
    printf("Enter a sentence: ");
    reverseSentence();
    return 0;
}

void reverseSentence() { //(1)
    char c;
    scanf("%c", &c); //input: abc (2)

    if (c != '\n') { (3)
        printf("%c-",c); //output1: a-b-c- (4)
        reverseSentence(); // call reserseSentence (5)
        printf("%c", c); // output2 will return after output1 finish : cba (6)
    }
}

ДИСПЛЕЙ : ab- c -cba

В void reverseSentence() программа будет работать:

1 -> 2 - > 3 -> 4 -> 5 -> 1 -> 2 -> 3 -> 4 -> 5 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 5 -> 6 -> 5 -> 6

Можете ли вы объяснить, как это работает? Почему переменная c может хранить все значения?

Ответы [ 5 ]

2 голосов
/ 20 марта 2020

Проблема здесь заключается в понимании того, как работают локальные переменные. Я буду использовать упрощенную модель, где стек используется только для локальных переменных.

Когда main вызывает reverseSentence, локальная переменная (c) выделяется в стеке:

+--------+
|   c    | <------current running copy of reverseSentence
+--------+
| main   |

После некоторых заявлений reverseSentence снова вызывает reverseSentence. Таким образом, в стеке создается следующая копия:

+--------+
|   c    | <------current running  reverseSentence
+--------+
|   c    | <------previous running reverseSentence
+--------+
| main   |

По мере того, как выполняется все больше и больше рекурсивных вызовов, стек получает большее число c переменных.

Когда reverseSentence возвращается, локальные переменные для этой работающей версии уничтожаются.

+--------+
| xxxxxx |  <----- reverseSentence that returned
+--------+
|   c    | <------current running copy of reverseSentence
+--------+
| main   |

На самом деле модель немного сложнее. В зависимости от архитектуры процессора, стек может содержать адреса возврата или указатели на контексты этетера. Но в качестве первой модели работы локальных переменных этого должно быть достаточно.

1 голос
/ 20 марта 2020

Я думаю, что картинки будут более четкими, f означает обратное предложение.

enter image description here enter image description here enter image description here

0 голосов
/ 20 марта 2020

Функции не используют фиксированные области памяти для своих переменных. Каждый раз, когда вызывается функция, она получает новые области памяти для использования для своих переменных.

Способ, которым большинство систем реализует это, заключается в том, что вся программа имеет зарезервированную область памяти, называемую стек, Существует указатель стека (SP), который указывает текущую часть стека, где используется. Всякий раз, когда функция запускается, она меняет SP так, чтобы он указывал на новую область в стеке. Затем он сохраняет все свои локальные переменные в местоположениях относительно нового значения SP, таких как SP + 4, SP + 8, SP + 24 и т. Д. Когда функция возвращается, она восстанавливает SP к своему предыдущему значению.

Таким образом, c при каждом вызове reverseSentence находится в другом месте.

Чаще всего указатель стека начинается с некоторого высокого адреса, определяемого операционной системой и программным загрузчиком, и он растет «вниз», что означает, что, когда функции требуется больше места в стеке, она вычитает некоторое число из указателя стека, чтобы получить более низкое значение адрес. Когда функция возвращается, она меняет ее, добавляя тот же номер (или загружая предыдущее значение указателя стека из места, где оно было сохранено).

0 голосов
/ 20 марта 2020

char c не хранит данные, каждый раз, когда он будет читать один символ с scanf и печатать его, а затем, потому что это рекурсивная функция, сначала go будет до последнего символа вашего ввода и печатать их от первого к последнему.

эта программа не меняет предложение на обратное, поскольку предложения нет, просто читает какой-то символ и печатает их с последнего на первый с помощью рекурсивной функции.

но этот код занимает слишком много времени и не предлагается, вместо этого вы можете определить строку и принять ее в качестве входных данных, а затем распечатать ее в порядке от последнего к первому (кроме \0), но даже этот метод не меняет предложение как на вашу программу, так и на этот метод печати от последнего к первому.

0 голосов
/ 20 марта 2020

scanf() будет съедать по одному символу за раз, поэтому каждый раз, когда reverseSentence() повторяется, он будет go до следующего, пока не достигнет новой строки, а затем тест if не проходит и рекурсия заканчивается. Поскольку по тому, как работает рекурсия, последний экземпляр выполняет последние printf, и поэтому вы получаете cba на выходе.

В некотором смысле вы можете рассмотреть возможность ввода "ab c" как ошибка: причина в том, что, как указано, программа будет вводить только один символ за раз в c. Это не очень хороший способ обработки пользовательского ввода в целом: было бы лучше сделать его массивом, в который обрабатывается вся входная строка. Введение рекурсии в это просто делает его беспорядочным без причины.

...