我想用C语言创建一个用户输入的程序,我无法理解循环的逻辑。
for ( c = 2 ; c <= n - 1 ; c++ )
程序代码如下: -
#include<stdio.h>
#include<conio.h>
void main()
{
int n, c;
printf("Enter a number to check if it is prime\n");
scanf("%d", &n);
for ( c = 2 ; c <= n - 1 ; c++ )
{
if ( n % c == 0 )
{
printf("%d is not prime.\n", n);
break;
}
}
if ( c == n )
printf("%d is prime.\n", n);
getch();
}
我使用了for循环,它将在for循环中结束n - 1
的语句。如果我将提供输入11
,那么它最终会在11 - 1 = 10
上,然后它将如何放弃if(c == n) { printf("%d", n);
的逻辑?
答案 0 :(得分:6)
如果我将提供输入
11
,那么它最终会在11 - 1 = 10
上结束,那么它将如何放弃if(c == n) { printf("%d", n);
的逻辑?
现在正确理解你的for循环条件:
for ( c = 2 ; c <= n - 1 ; c++ )
^^^^^^^^^^^^
2 <= 11 - 1 -> True // {for block executes }
3 <= 11 - 1 -> True // {for block executes }
:
:
9 <= 11 - 1 -> True // {for block executes }
10 <= 11 - 1 -> True // {for block executes }
11 <= 11 - 1 -> False breaks //{And Now for block NOT executes}
if (c == n)
^^^^^^
11 == 11 -> True // {if block executes}
根据for循环条件c <= n - 1
,当c
值等于n
时,循环中断。因此,如果n
等于11
,c = 2
到c = 10
的循环条件为真,则每次迭代c
增加1(使用c++
增量)当c
变为11
(或者说n
)时,条件c <= n - 1
变为false并且循环中断。
如果条件(for循环后)c
值与n
进行比较。那就是:
if ( c == n )
// 11 == 11 that is true
对于n
= 11
,如果条件评估为真,则变为c
= 11
,如果执行则与printf()
相关联。
同样重要的是要理解,当c = n
是素数时,for循环仅终止n
,但如果假设n
是非素数,那么 - 由于for循环中嵌套c
块中的n - 1
语句,循环将因break;
值小于if
而中断。
for( c = 2; c <= n - 1; c++ )
{
if(n % c == 0)<=="for Non-prime `n`, if condition will be true for some `c < n - 1`"
{ ^^^^^^^^^^^ True
printf("%d is not prime.\n", n);
break; <== "move control outside for-loop"
} // |
} // |
// <---------+ // if break; executes control moves here with c < n - 1
if (c == n)<== "this condition will evaluates FALSE"
^^^^^^^^ False
例如,如果n = 8
,那么在for循环的第一次迭代中,如果条件c = 2
的计算结果为if(n % c == 0)
== if(8 % 2 == 0)
,那么值为if( 0 == 0)
的for循环if-block中的true和break;
语句将控制移到for-loop之外(如图所示)。
因为此循环时间因c <= n - 1
条件而未终止但由于if(n % c == 0)
而被制止,因此外部for循环c
值小于n
因此{ {1}}评估为False。
答案 1 :(得分:2)
for循环从c = 2
循环到c = n - 1
,除了命中break
语句。如果是这样,它将跳出循环。如果你从未破坏,那么在循环之后你的c
实际上将是n
。
这就是原因。循环的工作方式如下:
c = 2
(c <= n - 1)
如果为true:执行循环体
if false:跳过循环c
增加一个示例:假设您的n
为3。
c
设置为2,现在为c == 2
和n == 3
2 <= 3 - 1
为真,因此循环体将被执行c == 3
和n == 3
3 <= 3 - 1
是假的,所以我们现在不执行循环体并跳出循环c == 3
和n == 3
以及c == n
之后因此,如果我们从未点击break语句c
将在循环后等于n
。如果 n不是素数,我们点击中断语句。如果我们中断c
将错过至少一个增量,因此在循环后将c < n
。现在c == n
将评估为false,并且if ( c == n )
的if语句主体将不会被执行。
现在到if ( n%c == 0 )
。 n%c
表示n
模c
,因此n
的剩余部分由c
表示。如果此余数为0,则c
是n
的整数除数。因此,在循环中,您对任何大于1且小于n
的除数进行n
测试。
如果n
的除数除了1和它本身,n
不能是素数。因此,如果您使用c
点击任何1 < c < n
,n%c
等于0 n
就不能成为素数。
提示:您不必测试大于√n
的除数。
答案 2 :(得分:1)
您假设c
最终为n - 1
不正确。如果您使用调试器逐步执行程序,则应该在循环结束时看到n == 11
,c == 11
。
如果我们没有提前中断那么循环体执行的最后一次确实是c == n - 1
然后c
然后递增并且循环不变测试失败所以在循环c == n
之后。
答案 3 :(得分:0)
当你说一个数字是素数时,请考虑它意味着什么。
对于每个n>1, n<p
,r = 0
的余数p/n = r
,数字p为素数。
因此,这个循环遍历每个值(c)范围[2..p-1]
,测试剩余部分。
int isprime = 1; //use a flag to indicate prime, assume prime until proven otherwise
for ( c = 2 ; //initialize c=2, the first value in the range [2..p-1]
c <= n - 1 ; //check whether c is still in the range [2..p-1]
c++ ) //increment c to the next value in the range [2..p-1]
{
if ( n % c == 0 ) //modulo '%' is the remainder of the integer division
{
isprime = 0;
break;
}
}
printf("%d %s prime.\n", n, isprime?"is":"is not");
不是通过检查循环计数器的副作用来测试数字是素数,为什么不在循环之前设置一个标志,然后在最后测试它作为素数的决定?结果是代码不那么脆弱,容易出错,而且更清晰。
想要节省大约一半的工作量?测试n%2
后,我们知道没有数字k,k*2=n
,对吗?所以检查范围[2..p/2]
,并将循环更改为,
for( c = 2; c <= n/2; c++ )
你能想到一个小于n/2
的数字吗?
查找多个素数的有趣算法是Sieve of Erastosthenes。