C - Counting numbers - c

I am a coding-beginner and would like to hear your advice relating to following solution of this exercise:
Write a program that loops prompting for positive or zero integers of data type long. Then the number of digits the integer consists of (in decimal representation) should be printed to stdout. Entering a negative number immediately stops the program.
Output examples: 0 has 1 digit. 999 has 3 digits. etc.
I've written the code below and according to the tests I did, the program fulfills all given tasks. But what do you think about it? How can I improve it?
(And I also think that I am not allowed to use any finished helpful function in any c-library. It is just 'plain' C coding or so. Idk how to describe it.)
(The programming language is C)
#include <stdio.h>
int main(void)
{
long number;
int n=0;
do
{
printf("Enter a number: ");
scanf_s("%ld", &number);
if (number > 0)
{
while (number != 0)
{
number /= 10;
n++;
}
}
else if(number == 0){
n = 1;
}
else {
exit();
}
printf("The number you've entered has %d digits.\n\n",n);
n = 0;
} while (getchar() != 'EOF');
return 0;
}

That getchar it's useless because EOF it's to say that a file it's over and you're not reading an file. Change that to while(number >=0).

Related

Why does my program print something before it ends when I press ctrl + D?

So I wrote a simple program that converts a decimal to binary, that only accepts positive whole numbers. So numbers like -2 and 1.1 would output "Sorry, that's not a positive whole number." It infinitely asks the user to input a number until the user presses ctrl + D. However when I tested it it prints out the "Sorry..." statement before it ends the program.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
void DecToBin(int userInput){
int binary[32];
int i = 0;
while (userInput > 0) {
binary[i] = userInput % 2;
userInput /= 2;
i++;
}
for (int j = i - 1; j >= 0; --j) {
printf("%d", binary[j]);
}
}
int main(void) {
double userDec;
int temp;
printf("Starting the Decimal to Binary Converter!\n\n");
while(!feof(stdin)) {
printf("Please enter a positive whole number (or EOF to quit): ");
scanf("%lf", &userDec);
temp = (int)(userDec);
if ((userDec > 0) && (temp / userDec == 1)) {
printf("\n\t%.0lf (base-10) is equivalent to ", userDec);
DecToBin(userDec);
printf(" (base-2)!\n\n");
}
else {
printf("\tSorry, that was not a positive whole number.\n");
}
}
printf("\n\tThank you for using the Decimal to Binary Generator.\n");
printf("Goodbye!\n\n");
return 0;
}
(All the tab and newlines are just how it's supposed to be formatted so don't pay attention to that)
So from what I'm understanding, my program reads ctrl + D as the else in my while loops. So, any idea why that is?
It seems like you think C-d would trigger some kind of break in the code. Like the keyword break. This is not true.
Read this post to see what's happening when you press C-d: https://stackoverflow.com/a/21365313/6699433
That does not cause anything special to happen in the C code. scanf will simply not read anything. After the scanf statement, the code will continue as usual, so the code WILL unconditionally enter the if statement.
This is also a pretty severe thing, because you'll be using userDec uninitialized. scanf returns the number of successful assignments, and you should always check the return value. So in your case you want this:
if(scanf("%lf", &userDec) != 1) { /* Handle error */ }
Because if scanf does not return 1, userDec is unassigned.
To achieve what you want, simply do this:
if(scanf("%lf", &userDec) != 1)
break;

How do I make the numbers in this C program print in the correct order and not in reverse?

I am new to C so I am having a little difficulty!
I want to take an integer input from the user and add 7 to each of the digit in the input. All of that works, but the digits are printing in the reverse order.
How do i make the digits print in the correct order? I checked other similar questions on Stack overflow but it does not seem to work. Thanks in advance!
int main(void)
{
int numToEncrypt;
printf("Please input a 4-digit number you wish to encrypt: ");
scanf("%d", &numToEncrypt);
while (numToEncrypt > 0)
{
int digit = numToEncrypt % 10;
// do something with digit
digit = (digit + 7)%10;
numToEncrypt /= 10;
printf("number is: %d \n",digit);
}
}
)
Converting the string input to an integer and back is pointless. Just work with the data as a string. eg:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int c;
if( getenv("V") ) {
printf("Please input the number you wish to encrypt: ");
fflush(stdout);
}
while( (c = getchar()) != EOF ) {
if( isspace(c) ) {
fflush(stdout);
} else if( isdigit(c) ) {
c = '0' + (c - '0' + 7) % 10;
} else {
fprintf(stderr, "Invalid input: %c", c);
return EXIT_FAILURE;
}
putchar(c);
}
}
Note that a huge advantage of doing this is that it is easy to work with ten million digit integers. You will not be able to do that using scanf to convert the string into an integer.
One way is using a variable to specify which digit to process.
#include <stdio.h>
int main(void)
{
int numToEncrypt;
int delta = 1000; // for 4-digit number
printf("Please input a 4-digit number you wish to encrypt: ");
scanf("%d", &numToEncrypt);
while (delta > 0)
{
int digit = (numToEncrypt / delta) % 10;
// do something with digit
digit = (digit + 7)%10;
delta /= 10;
printf("number is: %d \n",digit);
}
}
As this is homework, you could use recursion:
#include <stdio.h>
void print_recursive(int num)
{
// print leading digits
if (num>9)
{
print_recursive(num/10);
}
// print last digits
printf("number is: %d\n", (num+7)%10);
}
int main(void)
{
int number;
printf("Please input a 4-digit number you wish to encrypt: ");
scanf(" %d", &number); // note: You should check the return value!
print_recursive(number);
}
It is not limited to 4 digits.
For a simple program like this, one usually does not bother with a lot of design. However, it is also beneficial to practice software design on simple problems like this, since the knowledge extends to more complicated programs. This is an application of divide and conquer (as a problem solving strategy, not the computer algorithm). The idea being that smaller problems are simpler than larger ones.
In this case, you consider encapsulating the work of "encrypting" to a function, and have the function return the encrypted value. We'll just implement a stub for now, and fill it in later.
int encryptBy7(int input) {
int output = 0;
return output;
}
In addition, we can encapsulate the work of "printing" to a function. And, this is your actual question, if we think about it critically.
void printDigitByDigit(int num, const char *msg) {
printf("stub\n");
}
So your main program would look like:
int main(void) {
int numToEncrypt;
int numEncrypted;
printf("Please input a 4-digit number you wish to encrypt: ");
scanf("%d", &numToEncrypt);
numEncrypted = encryptBy7(numToEncrypt);
printDigitByDigit(numEncrypted, "number is");
return 0;
}
So, your algorithm to encrypt seems to work, so let's just code that up in a way that it stores it as a number.
int encryptBy7(int input) {
int output = 0;
int pow10 = 1;
/* Original program didn't deal with 0 */
if (input == 0) return 0;
while (input > 0) {
int digit = input % 10;
// do something with digit
digit = (digit + 7)%10;
input /= 10;
// build output
output += digit * pow10;
pow10 *= 10;
}
return output;
}
So, now we get to the meat of your question, which is about how to print out the digits starting with the most significant digit. If we see how we built up the output in the previous function, we can reverse the same process of looking at the powers of 10 to find the most significant digit, and then work backwards from there.
void printDigitByDigit(int input, const char *msg) {
int pow10 = 1;
int x = input;
// Find the position of the most significant digit
while (x > 10) {
pow10 *= 10;
x /= 10;
}
// Divide by the input appropriate power of 10 to
// find and print the corresponding digit
while (pow10 > 0) {
int digit = (input / pow10) % 10;
printf("%s: %d\n", msg, digit);
pow10 /= 10;
}
}
Of course, you are free to choose to try to do this as a single program inside of main as you had originally attempted, and the result would probably be a shorter program. I'll leave that as an exercise. However, I would argue that breaking up the program into tasks will provide you more benefit in the long run, and itself is a problem solving tool. Each function becomes easier to think about, and thus an easier problem to solve.

How to handle number too big on input in C?

my task is to make a sum of digits of a given number (without knowing its size). All I know is that the number is natural positive (including 0), so 0,1,2,3,4....10^x. The number will be given on stdin, so probably scanf is a solution. I know how I would do the sum, but I dont know how to store (some people suggested not to store) this number because even long long might not be enough if the number is too big.
Please answer more accurate, I'm C beginner. Thanks
If the input number can be arbitrarily large, it is indeed better not to try and convert it as a number but to operate on the digits typed. Note that this method always works anyway:
#include <stdio.h>
int main() {
long sum = 0;
int has_number = 0;
for (;;) {
int c = getchar(); // read the next byte from input
if (c >= '0' && c <= '9') {
sum += c - '0'; // add the digit value
has_number = 1;
} else {
if (has_number) {
printf("sum=%ld\n", sum); // output the current sum and
has_number = 0;
sum = 0; // reset the sum to zero
}
if (c == EOF)
break; // stop at end of file
}
}
return 0;
}
The above program can handle very large numbers, up to at least 200 million digits.

Confusing behavior with EOF and loops in C [duplicate]

This question already has answers here:
Why is scanf() causing infinite loop in this code?
(16 answers)
Closed 6 years ago.
I'm writing a C program that reads an undefined amount of integers from the keyboard. No limits. The program has a loop that reads integers with scanf and stores the lowest and highest value to display. If the user enters a negative number or non integer, the loop ends and displays info (lowest and highest value).
NOTE: I DO NOT WANT USE BUILT IN FUNCTIONS LIKE "ISDIGIT" OR "FGET". No idea what they are and I don't want to "cheat".
I found out that my EOF value is -1. I tried putting "while(scanf("%d", &num) > -1)" in my loop. This just does nothing if you enter a char(keeps reading and never ends loop). It sometimes breaks the loop if you enter a double negative such a "--2". It doesn't work, anyways.
My problem is with my programs confusing behavior with my current code. Sometimes it does not keep or read a zero. Sometimes it only stores and displays the second highest value. Sometimes it display the second to highest or lowest value after I enter an character or symbol to trigger an end to the loop. Other times it works just fine. I tried some more logical statements to force the min to be zero if it's not equal to 1 and less than 1, but that didn't work either.
An example of the weird behavior...
Enter some integer values, EOF to quit...
0
1
2
3
4
e
not an int
The minimum value is 0
and the maximum value is 3
Can anyone explain why this is happening and offer a solution and/or hint? I've been searching and googling for hours now.
Thank You!
Here is my code...
int min;
int max;
int num;
printf(" Enter some integer values, EOF to quit...\n");
scanf("%d\n", &num);
min = max = num;
while(scanf("%d", &num) == 1)
{
if(num > max)
{
max = num;
}
else if(num < min)
{
min = num;
}
scanf("%d\n", &num);
}//while(scanf("%d", &num) == 1);
printf(" not an int \n");
printf(" The minimum value is %d\n", min);
printf(" and the maximum value is %d\n", max);
You can make this "work" with scanf, but it won't really work. scanf is ill advised for a large number of reasons.
For example, let's say we did this:
printf("Enter some integers, or ctrl-D to quit.\n");
while(scanf("%d", &input) != EOF) {
if(input > max) {
max = input;
}
else if(input < min) {
min = input;
}
}
Seems sensible, scanf returns EOF if it doesn't have any input. And it seems to work.
$ ./test
Enter some integers, or ctrl-D to quit.
230
-238
5
max: 230, min: -238
But what if we give it something that isn't a number?
$ ./test
Enter some integers, or ctrl-D to quit.
230
-238
5
ldsfkj
^D
^D
^D
^C
Why won't it stop? If it fails to read what's required, it leaves it on the stdin buffer. It tries to read ldsfkj, fails because it's not an integer, returns 0 (not EOF) because it didn't match anything. But ldsfkj is still in the buffer, so when it loops again it reads it again and fails again. This is the big flaw in scanf.
Ok, what if we check that it scanned something?
while(scanf("%d", &input) == 1) {
...
}
Again, seems to work great... until we enter something that isn't an integer. Then it just stops because scanf failed. This isn't the behavior we want.
$ ./test
Enter some integers, or ctrl-D to quit.
2039
-203
23.4
max: 2039, min: -203
The safe thing to do is to read input line by line and process it with sscanf. This separates reading the line from parsing the line. We don't have to worry about things getting stuck in the buffer, and we can do more with the parsing, like giving the user an error message.
printf("Enter some integers, or ctrl-D to quit.\n");
char line[256];
while(fgets(line, 256, stdin) != NULL) {
if( sscanf(line, "%d", &input) != 1 ) {
puts("Sorry, I don't understand that");
continue;
}
if(input > max) {
max = input;
}
if(input < min) {
min = input;
}
}
Note that we always check both min and max because it's now possible for the input to be both.
Note that we're using fgets instead of gets because gets will not limit its input to the size of the string, it can easily overflow its buffer.
The second part is making min/max code simpler. Instead of making the first number a special case that's both min and max, assign the largest possible integer to min, and the smallest possible integer to max. Then the first input is guaranteed to be both the min and max. These limits can be found in limits.h.
Here it is all together.
#include <stdio.h>
#include <limits.h>
int main() {
int min = INT_MAX;
int max = INT_MIN;
int input;
printf("Enter some integers, or ctrl-D to quit.\n");
char line[256];
while(fgets(line, 256, stdin) != NULL) {
if( sscanf(line, "%d", &input) != 1 ) {
puts("Sorry, I don't understand that");
continue;
}
if(input > max) {
max = input;
}
if(input < min) {
min = input;
}
}
printf("max: %d, min: %d\n", max, min);
}
There is a small glitch in that program. I leave it as an exercise for you to find it and fix it.

Make loop stop by pressing dot

I need to write a program that asks you to enter numbers and when you press dot it will end the loop and display how many numbers are positive and how many are negative, like for example 4 5 -9 .
The program should show 2 numbers are positive and 1 is negative, but that isn't my problem. I'm stuck at the part where the loop should stop when I press dot, and bear in mind we are at the starter ages of programming so I can't be using fancy stuff.
As you can see here I tried giving a variable two types (char and float) but that doesn't work I think because it uses the value of the character instead of the numbers themselves.
int main()
{
float p, n;
char a;
n = 0;
p = 0;
do
{
printf("type a number");
scanf("%s&%f", &a);
if (a < 0)
{
n = n + 1;
}
else if (a > 0)
{
p = p + 1;
}
else
{
}
}
while (a != '.');
printf(" positive numbers are %2.0f \n negative numbers are %2.0f", p, n);
return 0;
}
Running your code through the popular online c compiler here:
http://www.tutorialspoint.com/compile_c_online.php
Your code ran as expected. What happens when you type "."?
EDIT: (Solution)
The problem was that when you input a negative number,
a = '-'
which has an integer value greater than zero, hence not triggering the negative case.
The solution then, is to check for the negative sign:
if (a == '-') {...}
Also, note that the '.' entered to terminate the loop is being counted as a positive number.
You should just read the input into a string and convert it to an integer if the first character isn't a '.'. Something like this:
printf("type a number\n");
scanf("%s", a);
if (a[0] == '.') {
break;
}
i = strtoul(a, NULL, 10);
Then you can see if i is positive or negative. Declare a as a char[10] or something.

Resources