I am currently trying to do the CS50 course. I am trying to make a do-while loop for the 1st problem set, but i throws back an error. Help would be great, thanks!
#include <cs50.h>
#include <stdio.h>
int main(void)
{
do
{
printf("Enter a positive integer no greater than 23: \n");
int n = get_int();
}
while ( int n < 0 || int n > 23);
}
$clang mario.c
mario.c:12:13: error: expected expression
while ( int n < 0 || int n > 23);
^
mario.c:12:13: error: expected ')'
mario.c:12:11: note: to match this '('
while ( int n < 0 || int n > 23);
^
2 errors generated.
Declare n only once, outside the do-while loop:
int n = -1;
do
{
printf("Enter a positive integer no greater than 23: \n");
n = get_int();
}
while (n < 0 || n > 23);
we never define a variable inside
expressions like if or while and For loop
this is only possible in other languages like C++ |;
Your problem lies in the fact that you have:
Declared n inside your while loop (This is not allowed in C89, but is grudgingly allowed in later versions)
Declared n twice in the while section.
The idea of declaration is to show the compiler, that the variable name present is not garbage but is actually a variable. The compiler generally follows fixed rules and does not look for variable names within the while/for loops (this is for optimization purposes). Also the second time that you declared n the compiler is now confused as you have stated a variable named n already exists.
PS: I believe you wished to say that n lies within the bounds of 1 and 22 If you wished to say this the correct expression would involve AND (&&) and not OR (||) ie, while ( int n < 0 && int n > 23).
Related
The example in this question seems to work only for fixed-length arrays, however the similar code below from https://frama-c.com/html/acsl.html doesn't seem to pass. As soon as I change the code to be include the requirement && n == 42 (or any other positive integer) it passes.
When it fails it says [wp] [Alt-Ergo 2.4.1] Goal typed_set_to_0_loop_invariant_established : Timeout (Qed:1ms) (1') (cached)
/*#
requires \valid(a+(0..n-1));
assigns a[0..n-1];
ensures
\forall integer i;
0 <= i < n ==> a[i] == 0;
*/
void set_to_0(int* a, int n){
int i;
/*#
loop invariant 0 <= i <= n;
loop invariant
\forall integer j;
0 <= j < i ==> a[j] == 0;
loop assigns i, a[0..n-1];
loop variant n-i;
*/
for(i = 0; i < n; ++i)
a[i] = 0;
}
Any tips on how to proceed / what the intended behaviour/flags are?
Actually, the loop invariant 0 <= i <= n is not true if n is strictly negative. A loop invariant must hold the first time you reach the loop (this is what the "established" part means, as opposed to the "preserved" part in which you must check that it holds at the end of any loop step, assuming it was true at the beginning of said step), even if you don't end up entering the loop at all (which is obviously the case here if n<0). You must thus add a requires n >=0; in the contract of the function.
EDIT
I forgot to mention that another solution is of course to make n and i unsigned (or even better to #include <stddef.h> and use size_t): this way, you are guaranteed a positive number without having to write an additional requires)
I have done some experiments using expressions. When I am working with some code, I found this unusual thing.
First trial
int i = 3;
int j = 5;
j >= i;
printf("Output1 = %d\n", i);
printf("Output2 = %d", j);
when I compiled this code I got error messge.
Second trial
int i = 3;
int j >= i;
printf("Output1 = %d\n", i);
printf("Output2 = %d", j);
return 0;
This also give me an error message.
Third trial
int i = 3;
int j = 5 >= i;
printf("Output1 = %d\n", i);
printf("Output2 = %d", j);
1) If i <= 5 output will be
Output1 = 3
Output2 = 1
2) If i > 5 output will be
Output1 = 3
Output2 = 0
Why my first trial and second trials give errors and third one compiled unharmly?
I need some explanation.
Converting comments into an answer.
In the first trial, the statement j >= i; has no effect on the computation so it is ignored by the compiler. Your compiler settings might convert that warning into an error, which is a Good Thing™.
The second trial is an outright syntax error. You can't use a comparison in place of an initializer.
The third trial is fine and gives the expected results. The value of a comparison such as 5 >= i is either 0 if the comparison is false or 1 if the comparison is true.
But in the third one, there is also a comparison in the initializer but it didn't give an syntax error or compile error
In the third one, you have:
int j = …something…;
which is a valid initializer (because the …something… is a valid comparison). Initializers start with an = symbol. In the second, you have nt j >= i; — this does not start with = and hence is invalid. Note that trying int j == i; would also be invalid; the symbol is == and not =.
See C11 §6.7.9 Initialization and §6.7 Declarations for the syntax of intializers.
Then it means comparison which is in initializer is true it outputs 1. If false it output 0.
Yes, the comparison in the initializer generates either 1 (true) or 0 (false) — that is the value assigned to j, as your tests showed.
I am writing a code in which a input is taken to run some no of test case and in each test case we have to iterate the number through each number and we have to divide it with the initial number taken and if it gives remainder 0 then we need to increment the count otherwise we need not increment the count and at last we will print the count.
The number 12 is broken into two digits, 1 and 2. When 12 is divided
by either of those digits, the calculation's remainder is 0; thus, the
number of evenly-divisible digits in 12 is 2
Compiler Message
Floating Point Exception
The code is given below and when running in a c compiler the program abruptly stops after taking the input.
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
int main(){
int t;
int n[t],b,rem;
int count =0;
scanf("%d",&t);
for(int a0 = 0; a0 < t; a0++){
scanf("%d",&n[a0]);
}
for(int i=0;i<t;i++){
b =n[i];
while (n[i]) {
rem = n[i] % 10;
if(b%rem == 0)
count++;
n[i] = n[i] / 10;
}
printf("%d\n",count);
}
return 0;
}
.
You can create an array of a given size before the size being set.
Another error (logical one), is that you didn't reset the counter for each number.
Your initial problem, is that you didn't pay attention of division by 0.
This may be a solution:
int main(){
int t;
scanf("%d",&t);
int n[t];
for (int a0=0; a0<t; a0++){
scanf("%d",&n[a0]);
}
for (int i=0; i<t; i++){
int count = 0;
int b=n[i];
while (n[i]) {
int rem = n[i] % 10;
if (rem!=0 && b%rem==0)
count++;
n[i] = n[i] / 10;
}
printf("%d\n",count);
}
return 0;
}
In your code, at the point you're writing int n[t], t is not initialized. As the initial value of an unitialized automatic local variable is indeterminate and using that invokes undefined behavior, so your code exhibits UB.
You need to move the definition of int n[t] after you successfully scan the value of t from user.
After that, from the property of % operator, quoting C11, chapter §6.5.6, (emphais mine)
The result of the / operator is the quotient from the division of the first operand by the
second; the result of the % operator is the remainder. In both operations, if the value of
the second operand is zero, the behavior is undefined.
so, you need to make sure, rem is not 0 while doing if(b%rem == 0). You should put a check on rem != 0 && .... to avoid this scenario.
That said, just a suggestion: VLAs are not the mandatory part of standard C anymore (C11 onwards), so you can make use of a pointer and allocate dynamic memory using malloc() and family.
When I use a for loop with a uint64_t as a counter, it gets stuck forever, even though the condition seems to be well defined.
Offending MCVE
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t i;
for (i = 15; i >= 0; i--) { printf("%"PRIu64" ", i); }
return 0;
}
Partial output
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 18446744073709551615 18446744073709551614 18446744073709551613 18446744073709551612 18446744073709551611 18446744073709551610 18446744073709551609 18446744073709551608 18446744073709551607 18446744073709551606 18446744073709551605 18446744073709551604 18446744073709551603 18446744073709551602 18446744073709551601 18446744073709551600 18446744073709551599 18446744073709551598 18446744073709551597 18446744073709551596 18446744073709551595 18446744073709551594 18446744073709551593 18446744073709551592 18446744073709551591 18446744073709551590 18446744073709551589 18446744073709551588 18446744073709551587 18446744073709551586 18446744073709551585 18446744073709551584 18446744073709551583 18446744073709551582 18446744073709551581 18446744073709551580 18446744073709551579 18446744073709551578 18446744073709551577 18446744073709551576 18446744073709551575 18446744073709551574 18446744073709551573 18446744073709551572 18446744073709551571 18446744073709551570
It seems it's ignoring the stop condition, and so it rolls over.
However, when changing it to an "equivalent" while loop, everything works fine:
Correct MCVE
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t i = 16;
while (i--) { printf("%"PRIu64" ", i); }
return 0;
}
Complete output
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Am I missing something regarding the use of uint64_t counters in a for loop? Any help is greatly appreciated!
The condition i >= 0 is alwaays true if i is an unsigned type. Decrementing an unsigned zero will not produce a negative value, but the counter will wrap to the maximum representable number for the given type.
C represents ranges with an inclusive lower bound and an exclusive upper bound. For example, an array of N elements has indices 0 through N - 1. The upper bound itself isn't a valid array index.
This convention means that you use a value before incrementing it, but deceremt it before using it. Consider a simple stack:
stack[nstack++] = x; // push a value
x = stack[--nstack]; // pop a value
The same logic goes for loops: When you move forwards, use the value before you increment it:
for (var i = 0; i < N; i++) { use(i); }
When you move backwards, decrement first and then use it:
for (var i = N; i-- > 0; ) { use(i); }
This loop is equivalent to your while. The update section, which happens after processing the body, is empty here. The check is performed on the value before entering the loop; the loop body has the updated value.
This backwards loop might look awkward with the empty update section, but in other ways it is orthogonal to the forward version:
It uses the actual bounds; there's no need to start with N - 1;
It works equally well for arbitrary bounds as long as they follow the convention of inclusive lower and exclusive upper bound;
The test is a pure inequality, not a greater/less-then-or equal comparison.
The expression i >= 0 is always true if i is of an unsigned integer type. The alternative and simple way is to change it into:
uint64_t i;
for (i = 15; i != -1; i--) { ... }
This works no matter if i is a signed or an unsigned integer. In the uint64_t case, -1 will first get converted into 0xFFFFFFFFFFFFFFFF and then compared with i.
If you want to get rid of the compile warning, change it into:
i != (uint64_t)-1
but you need to ensure the uint64_t is exactly the type of i.
#include <stdio.h>
main() {
int n;
scanf("%d", &n);
int zz, count;
int i = 5;
while(zz >= 1) {
zz = n / i;
count += zz;
i = i * 5;
}
printf("%d", count);
}
This is code to find trailing 0's in factorial of a number.
It's giving different output in Ubuntu than on Windows.
You can find out at least a few of the issues by enabling warnings during compilation. In this case (output from clang -Wall -Wextra the_file.c):
tst.c:3:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main() {
^
tst.c:10:9: warning: variable 'count' is uninitialized when used here [-Wuninitialized]
count += zz;
^~~~~
tst.c:6:18: note: initialize the variable 'count' to silence this warning
int zz, count;
^
= 0
tst.c:6:9: warning: variable 'zz' is used uninitialized whenever function 'main' is called [-Wsometimes-uninitialized]
int zz, count;
~~~~^~
tst.c:8:11: note: uninitialized use occurs here
while(zz >= 1) {
^~
tst.c:6:11: note: initialize the variable 'zz' to silence this warning
int zz, count;
^
= 0
3 warnings generated.
You should fix all of those first.
I'm not sure exactly what you're asking, but there are a couple problems with your code I can point out:
Indent your code. Indenting code is mandatory.
Try to put whitespace around operators. It goes a long way towards making your code more readable.
Don't use scanf. You will be much happier if you avoid the entire scanf family of functions.
You're using zz and count without initializing them. C does not initialize variables to any particular value; you always must initialize them yourself.
You should really change main to int main. They do the same thing, but the latter is easier to read.
If you add some test cases explaining what your code is supposed to do, it will be easier to answer your question.
Uninitialized variable
int zz, count;
int i = 5;
while(zz >= 1) { // what is zz?
i = i * 5; overflows. Undefined behavior. Different result on different systems is not unexpected.
--
There is no need to compute the factorial. Just count the number of 5s in n.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
printf("%d", n/5);
}
15! --> 1307674368000
9! --> 362880
To have a trailing 0, the factual needs a product of some multiple of 5 and a multiple of 2. Every other number in the factorial combination is even and every 5th is a multiple of 5.
public static void main(String[] args) {
int n=23;
String fact= factorial(BigInteger.valueOf(23)).toString();
System.out.format("Factorial value of %d is %s\n", n,fact);
int len=fact.length();
//Check end with zeros
if(fact.matches(".*0*$")){
String[] su=fact.split("0*$");
//Split the pattern from whole string
System.out.println(Arrays.toString(fact.split("0*$")));
//Subtract from the total length
System.out.println("Count of trailing zeros "+(len-su[0].length()));
}
}
public static BigInteger factorial(BigInteger n) {
if (n.equals(BigInteger.ONE) || n.equals(BigInteger.ZERO)) {
return BigInteger.ONE;
}
return n.multiply(factorial(n.subtract(BigInteger.ONE)));
}