Сейчас на форуме: 2nd, morgot, Rio, CDK123, zds, tyns777, tihiy_grom (+5 невидимых)

 eXeL@B —› Программирование —› Хочу обсудить один пример по C++
Посл.ответ Сообщение

Ранг: 4.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 31 августа 2008 10:58
· Личное сообщение · #1

Наткнулся на одну книгу по C++/ Сам сейчас только в процессе изучения. Книга под DOS, поэтому проверять не стал исходники. Хочу обсудить пару листингов с теми кому интересно.
1. С первым мне все понятно. Пример находит все простые делители введенного числа.
После просмотра листинга все сошлось. Все работает. Происходит нормальный выход из программы
#include <iostream>
#include <math.h>
using namespace std;

void get_all_divisors(int n);
int get_lowest_divisor(int n);

int main() {
int n;


while(1) {
cout << "Enter a number (0 to quit): ";
cin >> n;
if (n == 0)
break;
get_all_divisors(n);
cout << endl;
}
return 0;
}

// Get all divisors function; use a loop
// to print all the divisors of n, by reiterative
// calls to get_lowest_divisor

void get_all_divisors(int n) {
int i;

while (1) {
i = get_lowest_divisor(n);
cout << i;
if (i == n) // If lowest divisor == n
break; // there are no more divisors,
cout << ", "; // Else, print comma and get
n = n/i; // lowest divisor of remaining
} // quotient.
}

int get_lowest_divisor(int n) {
int i;

double sqrt_of_n = sqrt(static_cast<double>(n));

for (i = 2; i <= sqrt_of_n; i++)
if (n % i == 0) // If i divides n evenly,
return i; // return i.

// If no divisor is found, return n itself.

return n;
}


2.Программа делает тоже самое-находит все простые делители. Немного беспорядочно их выдает, но не суть. А вот тут у меня возникли сомнения. Не ошибся ли автор книги. То, что я выделил жирным, а именно выход из программы, по-мойму не может быть осуществлен, т.к перед ним всегда будет вызвана рекурсивная функция get_divisors(n / i); в результате чего программа закончится последней инструкцией cout << n; ....Но, что будет дальше, когда выполнится эта инструкция ? Выхода то нет. Куда перейдет вообще управление программой.

#include <math.h>
using namespace std;

void get_divisors(int n);

int main() {
int n;

cout << "Enter a number and press ENTER: ";
cin >> n;

get_divisors(n);

return 0;
}

// Get divisors function
// This function prints all the divisors of n,
// by finding the lowest divisor, i, and then
// rerunning itself on n/i, the remaining quotient.

void get_divisors(int n) {
int i;
double sqrt_of_n = sqrt((double) n);

for (i = 2; i <= sqrt_of_n; i++)
if (n % i == 0) { // If i divides n evenly,
cout << i << ", "; // Print i,
get_divisors(n / i); // Factor n/i,
return; // and exit.
}

// If no divisor is found, then n is prime;
// Print n and make no further calls.

cout << n;
}



Ранг: 4.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 31 августа 2008 11:03
· Личное сообщение · #2

То есть в самом конце программы надо переместить выход под конец. Как думаете.
for (i = 2; i <= sqrt_of_n; i++)
if (n % i == 0) { // If i divides n evenly,
cout << i << ", "; // Print i,
get_divisors(n / i); // Factor n/i,
return; // and exit. ===========убрать и перенести в конец
}

// If no divisor is found, then n is prime;
// Print n and make no further calls.

cout << n;
return; // and exit. ===========сюда
}




Ранг: 247.7 (наставник), 3thx
Активность: 0.160
Статус: Участник
Халявщик

Создано: 31 августа 2008 13:03
· Личное сообщение · #3

jondos
Ты конечно МОЗГ!

or (i = 2; i <= sqrt_of_n; i++)
if (n % i == 0) { // If i divides n evenly,
cout << i << ", "; // Print i,
get_divisors(n / i); // Factor n/i,
return; // and exit.
}

Вишь этот код? тут цикл, который отработает и выйдет, т.к. функция рекурсивно вызывает саму себя и этот цикл так называемый якорь - то есть условие выхода

-----
Лень - это подсознательная мудрость




Ранг: 210.5 (наставник), 2thx
Активность: 0.140
Статус: Участник

Создано: 01 сентября 2008 11:52 · Поправил: arnix
· Личное сообщение · #4

Code:
  1. for (= 2; i <= sqrt_of_n; i++)
  2. if (% i == 0) { // If i divides n evenly, 
  3. cout << i << ", "; // Print i,
  4. get_divisors(/ i); // Factor n/i,
  5. return; // and exit.
  6. }


не хватает одного "{", [наверно] должно быть

Code:
  1. for (= 2; i <= sqrt_of_n; i++)
  2. if (% i == 0) { // If i divides n evenly, 
  3. cout << i << ", "; // Print i,
  4. get_divisors(/ i); // Factor n/i,
  5. }
  6. return; // and exit.
  7. }




Ранг: 25.3 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 01 сентября 2008 20:37
· Личное сообщение · #5

Да это вообще кривой код ))
На столько кривой, что работает без ошибок.
Ошибка только одна - в комментарии.
Не стоит читать его буквально. Он означает exit не из программы а из текущего вызова функции.
Та как функция рекруссивна, в данном случе return одначает возврат на "уровень выше", а выход в main произойдет после цаута }.



Ранг: 4.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 22 сентября 2008 04:13
· Личное сообщение · #6

Спасибо. Теперь дошло. Доп скобок не надо никаких. Все правильно. Я просто не понимал, что рекурсивная функция умная такая.
---------------------------------------------------------------------- -------------------------------
Кстати, вот такой моментик есть.
...............
x = get_a_string(p)
char *get_a_string(char *start_addr, char *dest) {
char *p = start_addr;
..............
Правильно ли я понял, чта выделенная жирным инструкция просто передает указателю p свойства указателя start_addr. Ведь после принятия аргумента (char *start_addr, char *dest) указатель start_addr можно использовать в дальнейшем теле функции. Или все-таки какой-то смысл есть в char *p = start_addr



Ранг: 45.7 (посетитель), 5thx
Активность: 0.020
Статус: Участник

Создано: 22 сентября 2008 07:51
· Личное сообщение · #7

>>char *p = start_addr;
>>просто передает указателю p свойства указателя start_addr.

Указатель это адрес .... и все... адрес это число.... если компилятор 32битный код генерирует то размер указателя 32бита... а то что у него есть доп. тэги компилятору что мол по этому адресу мы имеем память с типом char .. уже второе....


>>указатель start_addr можно использовать в дальнейшем теле функции. Или все-таки какой-то смысл >>есть в char *p = start_addr

обычно так делают для того что бы всегда иметь изначальный указатель на память ... но и при этом иметь удобный способ работы с этой памятью не теряя начальный указатель.... то бишь... предположим что у нас оба указателя указывают на нуль терминированую строку... и нам надо скопировать из старт адрес её в dest

Code:
  1. char *get_a_string(char *start_addr, char *dest) {
  2.  while(  *start_addr )
  3.       *dest++=*start_addr++;
  4.  *dest = '\0';
  5. }


При этом мы потеряли изначальные указатели на память start_addr и dest и соотвено скажем если память по указателю start_addr была выдела динамически и мы хотим иметь возможность в функции после копирования содержимого start_addr в dest её освободить ... то сделать мы этого не сможем то бишь надо было сохранить куда нибудь этот указатель перед работой с ним.... то бишь можно скажем вот так сделать было:

Code:
  1. char *get_a_string(char *start_addr, char *dest) {
  2.  char *= start_addr;
  3.  while(  *p)
  4.       *dest++=*p++;
  5.  *dest = '\0';
  6.   free( start_addr );
  7. }



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


 eXeL@B —› Программирование —› Хочу обсудить один пример по C++
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати