C中素数的平方

时间:2011-12-03 20:55:12

标签: c

我正在编写代码,要求从键盘输入两个正整数。第一个整数N在3-15的范围内是奇数,第二个整数N将具有初始值I.N将是数组的大小。从整数I开始在NxN数组的中心。如果我是素数,则在该正方形的位置打印数字I.否则在该位置打印三个星号。向右移动一个方格,并测试整数I + 1的素数。如果是素数则打印I + 1,如果不是则打印三个星号。继续逆时针方向穿过正方形,直到方形充满数字和三个星号,然后打印阵列。

这就是问题;我已经做了大部分工作,并且对如何制作数组感到困惑,如果有人可以查看我的代码,让我知道我是否正确设置了for循环。谢谢你的帮助。

#include <stdio.h>

int main(int argc,char* argv[]) {
    int N, I;

    printf("Enter an odd integer n between 3 and 15: ");
    scanf("%d", &N);

    printf("Enter an initial value i: ");
    scanf("%d", &I);

    int arr[N][N];
    int k = 1;
    int i = N / 2 + 1;
    int j = N / 2 + 1;

    while(k < N) {
            int s;

            for(s = 0; s < k; s++, i++, I++)
                    arr[i][j] = IsPrime(I) ? I : -1;
            for(s = 0; s < k; s++, j--, k++)
                    arr[i][j] = IsPrime(I) ? : -1;
            k++;
            for(s = 0; s < k; s++, i--, I++)
                    arr[i][j] = IsPrime(I) ? I : -1;
            for(s = 0; s < k; s++, j++, I++)
                    arr[i][j] = IsPrime(I) ? I :-1;
            arr[i][j] = IsPrime(I) ? I : -1;
            k++;

            if(IsPrime(i) == 1) {
                return i;
            } else {
                    printf("***");
            }
    }
            return 0;
}

int IsPrime(int n) {
    int i, count = 0;

    for(i = 1; i <= n; i++) {
            if((n % i) == 0) count++;
    }
}

1 个答案:

答案 0 :(得分:10)

好的,所以这里有很多错误,还有很多可以解释的。让我们从真正明显的东西开始,阻止它甚至运行,然后继续前进。 我将使用C89,所以我将在每个方法的开头声明所有我的局部变量。我将使用gcc 4.6.1,并使用-W -Wall -ansi -pedantic -g -lm进行编译。 我们很快就需要-lm - 它链接到数学库。

IsPrime()

所以,你的IsPrime(int n)似乎遗漏了底部的一些部分。因此,我甚至不能说它是否会起作用。

让我们通过将int IsPrime(int n);放在#include stdio.h正下方的文件顶部来向前声明。虽然我们正在努力,但我们还要添加更多内容:

#include <stdlib>
#include <math.h> /* For sqrt() */

现在,让我们用一些应该工作的东西替换方法的主体(好吧,你没必要,但我会因为我看不到你方法的其余部分):

int IsPrime (int n) {
  int i, sqrtN;

  if (n < 2) { return 0; } /* 1, 0, and negatives are nonprime */
  if (n == 2) { return 2; }
  if ((n % 2) == 0) { return 0; } /* Check for even numbers */
  sqrtN = sqrt(n) + 1; /* We don't need to search all the way up to n */
  for (i = 3; i < sqrtN; i += 2) {
    if (n % i == 0) { return 0; } /* Stop, because we found a factor! */
  }
  return n;
}

main()和scanf()

您没有使用main()的参数,所以我们将其更改为int main(void) {。 当您致电scanf()时,您应该检查结果 - 它会返回成功匹配的内容数量,或EOF。您还应该检查它存储的值,因为您需要N具有特定范围而我才能为正。

所以,让我们尝试在main()

的开头使用它
int N, I;
int s;
int i, j, k;
int **arr; /* More on this later*/

printf("Enter an odd integer n between 3 and 15: ");
s = scanf("%d", &N);
if (s != 1) {
  printf("No proper input provided; program will now exit");
  return 0; /* Or we could use EXIT_SUCCESS, which is defined by stdlib */
} else if (N < 3 || N > 15) {
  /* I have assumed the range of 3 to 15 to be inclusive here */
  printf("I must be positive; program will now exit");
  return 0;
}

printf("Enter an initial value I: ");
s = scanf("%d", &I);
if (s != 1) {
  printf("No proper input provided; program will now exit");
  return 0;
} else if (I <= 0) {
  printf("I must be positive; program will now exit");
  return 0;
}

的malloc()

从您对问题的评论中,您似乎明白malloc分配内存但不一定是正确的语法,以便在此实例中执行此操作。 这就是int **arr;的用武之地。为了分配你的二维整数数组,现在我们有了N的合法值,我们可以做arr = malloc(N * sizeof arr[0]); 现在,malloc可能会失败,因此我们需要在调用之后检查arr != NULL。我们还没有完成!这只是你的数组的一个维度 - 我们只为N个指向一维数组分配了足够的内存,由arr指向。 所以我们必须循环并为那些指向指向的指针分配空间。

那么我们这样做:

for (s = 0; s < N; ++s) {
  arr[s] = malloc(N * sizeof arr[0][0]); /* Enough space for N integers */
  if (NULL == arr[s]) {
    /* We'll just quit instead of handling this gracefully... */
    /* ...because this is only an example */
    printf("Uh oh! Memory allocation failed! Let's run away!\n");
    return 0;
  }
}

免费()

现在,因为你已经分配了内存,所以当你完成它时你也需要释放它。在main方法的最后,您将需要一个循环来释放您为其分配空间的每个一维数组,然后您将需要释放arr本身。 像这样:

for (s = 0; s < N; ++s) {
  free(arr[s]);      
  /* I am paranoid about setting pointers to NULL */
  arr[s] = NULL;
}

free(arr);
arr = NULL;
/* It can matter if you are going on to do other things instead of exiting. */

return 0;

逻辑

所以,现在对于实际上意味着在数组中移动的循环。 您将从main返回i而不是打印出来。我很确定你打算把它打印出来,对吗?如果您需要打印整个网格作为网格,则需要在使用IsPrime()测试所有值后单独执行此操作。如果您只需要从中心开始以螺旋顺序打印出数字是否为素数(好,数字或 * ),那么您实际上并不需要arr一点都不。

现在,你计算数字的循环也是不正确的(对于初学者来说,它超出了数组的范围),但是我不愿意为你解决这个问题,因为那条逻辑就是你的意思家庭作业,所以请先尝试整理我在这里提到的所有内容,然后评论一下,如果你之后仍然坚持逻辑,我猜。

顺便说一句,我已经避免更改您的变量名称,但您可能要考虑不要混合Ii,并且通常更具描述性地命名。

螺旋逻辑

免责声明:可能有更好的方法,这就是我想到的。但它确实有用。

我想到的方式是中间正方形和它的右边之间有一条边,另一条边在该正方形和它上面的边之间,依此类推。这形成螺旋图案。如果你绘制它,你还会注意到在每个第二个角之后,下一个角之前的边数增加一(1,1,2,2,3,3)。如果我们记录当前一侧有多长,何时需要改变,我们走向何方,何时停止(我们知道有N * N个总平方,所以只计算你已经填写的方块到目前为止,这是相对简单的:

totalSquares = N * N;
currentSquare = 0;
currentSideLength = 1; /* Number of edges/transitions per side before we turn */
currentPositionOnSide = 0; /* How far down a side we are*/
increaseSideLength = 0; /* This keeps track of when to increase currentSideLength */
i = j = N / 2; /* The middle */
direction = 0; /* Which way we're going - using an enum here would be better for clarity */

while (currentSquare < totalSquares) {

arr[i][j] = IsPrime(I);
switch (direction) {
  case 0: /* Right */
    ++j;
    break;
  case 1: /* Up */
    --i;
    break;
  case 2: /* Left */
    --j;
    break;
  case 3: /* Down */
    ++i;
    break;
  default: /* So we can see if something silly goes wrong with the direction! */
    printf("WTH?\n");
    break;
  }

  ++currentSquare, ++I, ++currentPositionOnSide;

  if (currentPositionOnSide == currentSideLength) { /* We're at a corner! */
    ++increaseSideLength; /* Keep track of the number of turns */
    currentPositionOnSide = 0;
    direction = (direction + 1) % 4; /* Wrap around */
    if ((increaseSideLength % 2) == 0) { /* Increase every second corner */
      ++currentSideLength;
      increaseSideLength = 0;
    }
  }
}

/* Ultra crude formatting - you may want to do better than this */
for (i = 0; i < N; ++i) {
    for (j = 0; j < N; ++j) {
      if (arr[i][j] == 0) {
        printf(" *** |");
      } else {
        printf("%4d |", arr[i][j]);
      }
    }
  printf("\n");
}

现在,我已经检查过这是否有效,但我还没有测试#@!出于它 - 这是你的责任。此外,你显然需要添加这些变量或重用一些你已经拥有的变量(我真的建议使用名称很好的变量。)

此外,该代码通过让它返回n或0来滥用IsPrime()(0不是素数,你说我必须是正数,因此不需要使用-1),因此避免了所有{ {1}}检查。