我正在编写代码,要求从键盘输入两个正整数。第一个整数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++;
}
}
答案 0 :(得分:10)
好的,所以这里有很多错误,还有很多可以解释的。让我们从真正明显的东西开始,阻止它甚至运行,然后继续前进。
我将使用C89,所以我将在每个方法的开头声明所有我的局部变量。我将使用gcc 4.6.1
,并使用-W -Wall -ansi -pedantic -g -lm
进行编译。
我们很快就需要-lm
- 它链接到数学库。
所以,你的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()
的参数,所以我们将其更改为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
分配内存但不一定是正确的语法,以便在此实例中执行此操作。
这就是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
一点都不。
现在,你计算数字的循环也是不正确的(对于初学者来说,它超出了数组的范围),但是我不愿意为你解决这个问题,因为那条逻辑就是你的意思家庭作业,所以请先尝试整理我在这里提到的所有内容,然后评论一下,如果你之后仍然坚持逻辑,我猜。
顺便说一句,我已经避免更改您的变量名称,但您可能要考虑不要混合I
和i
,并且通常更具描述性地命名。
免责声明:可能有更好的方法,这就是我想到的。但它确实有用。
我想到的方式是中间正方形和它的右边之间有一条边,另一条边在该正方形和它上面的边之间,依此类推。这形成螺旋图案。如果你绘制它,你还会注意到在每个第二个角之后,下一个角之前的边数增加一(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}}检查。