Ошибка с совершенными числами? - PullRequest
1 голос
/ 01 марта 2011

В настоящее время у меня есть этот код, и он работает.

#include <stdio.h>

int isFactor(long number1, long number2)
{
  int isitFactor = (number2 % number1 == 0)?1:0;
  return isitFactor;
}

int isPerfect(int number)
{
   int counter;
   int sum;
   for (counter = 1; counter < number; counter++) 
      if (isFactor(counter, number)) 
         sum += counter;
   return (sum == number);
}

int main()
{
   int counter = 1;
   for (counter = 1; counter <= 100; counter++)
   {
      printf("", isPerfect(counter));
      if (isPerfect(counter)) 
         printf("%d\n", counter);
   }
}

Однако, если я вычеркну ненужную строку с printf в main (), он не даст никаких чисел .... Возможные причины?!

Ответы [ 2 ]

12 голосов
/ 01 марта 2011

Переменная sum в функции isPerfect не инициализирована.

6 голосов
/ 01 марта 2011

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

Вторая проблема (теперь исправленная с вашим редактированием) заключалась в том, что isFactor отсутствует.Хотя вы, вероятно, хотите использовать его как функцию, работает следующий код, который выдает два идеальных числа меньше 100, 6 и 28:

#include "stdio.h"

#define isFactor(c,n) ((n % c) == 0)

int isPerfect (int number) {
    int counter;
    int sum = 0;  // <-- note initialisation here.
    for (counter = 1; counter < number; counter++)
        if (isFactor(counter, number)) sum += counter;
    return (sum == number);
}

int main (void) {  // try to use one of the two canonical forms.
    int counter = 1;
    for (counter = 1; counter <= 100; counter++)
        if (isPerfect(counter)) printf("%d\n", counter);
    return 0;
}

И выясняет, почему оно можетработать с этим дополнительным printf, вот жизнеспособное объяснение.

При вызове функции локальные переменные размещаются в стеке просто путем уменьшения указателя стека.Ваш код сборки isPerfect, вероятно, просто имеет пролог, подобный:

sub %esp,8

, и затем вы используете память в% esp для counter и %esp + 4 для суммы.Без инициализации sum он начинается с того, что произошло в той области памяти, которая, вероятно, не равна нулю.

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

Затем, когда вы вызываете isPerfect, появляется хорошийвероятность того, что эти ячейки памяти будут отличаться от того, что было до того, как вы назвали printf, просто потому, что printf использовал их для своих собственных целей.

Если вам повезет (или не повезет, в зависимости отваша точка зрения), место в памяти, где будет sum, может быть даже нулевым.Но, тем не менее, это неопределенное поведение, и вы должны , а не полагаться на него - инициализировать sum явно, и ваши (немедленные) проблемы будут закончены.


Если это домашняя работа, не стесняйтесьигнорировать этот бит (на самом деле активно игнорировать его, так как вас могут поймать на плагиат).Вот как я бы реализовал функцию isPerfect в качестве первого среза.Он не вызывает функции для определения факторов, поскольку, хотя они, как правило, довольно быстрые, они не обходятся без затрат, и в любом случае можно сделать что-то такое простое в одной строке C.

int isPerfect (int num) {
  int i, left;
  for (i = 1, left = num; i < num; i++)
    if ((num % i) == 0)
      left -= i;
  return (left == 0);
}

Нет сомнений в том, что можно * сделать быстрее, но отдача от инвестиций довольно быстро падает после определенного момента.

...