C programming segmentation error - c

This is the code for finding the last digit of nth Fibonacci number
#include <stdio.h>
int main() {
long i, j, fib[1000];
fib[0] = 0;
fib[1] = 1;
scanf("%li", &j);
for(i = 2; i != 1000; i++)
{
fib[i] = (fib[i - 2] + fib[i - 1]) % 10;
}
printf("%li", fib[j]);
return 0;
}
It shows segmentation fault. How can I fix it?

The only reason I can see for this not working is that you're inputting a number that is outside of the range 0 <= j <= 999. This is due to the limit on your array variable: long fib[1000].
This can be fixed in one of two ways, depending on what you want:
You can add a check to make sure that the input value j is in range, and ask for another number if it isn't.
You can stop using an array variable, and only use three variables: one to store the current value, and two more to store the two previous values. These are updated as you calculate. A loop is still used with this approach.
#1 is the simplest to implement, as shown here:
while (1)
{
printf("j > ");
scanf(" %li", &j);
if (0 <= j <= 999)
{
break;
}
}
#2 is a bit more complex, but it effectively removes the arbitrary limit that j must be less than 1000 (and changes the limit so that j must be less than LONG_MAX):
// num_cache[0] is the number before the previous number
// num_cache[1] is the previous number to the current number
long num_cache[2] = { 0, 0 };
long current_fib = 1;
for (i = 2; i < j; i++)
{
// Push back the numbers
num_cache[0] = num_cache[1];
num_cache[1] = current_fib;
// Calculate the new number
current_fib = (num_cache[0] + num_cache[1]) % 10;
}
One of those solutions should fix your issue.

It appears that the segmentation fault is occurring due to inadequate checking of input values.
If the input to the program is not a valid number, then the value of j will be unchanged after the call to scanf(). Since this variable is uninitialized, this will result in undefined behaviour when you attempt to access the jth element of the fib[] array.
If the value of j is less than zero or greater than 999, you will be accessing a non-existent member of fib[] when you exit the for() loop. Your code should check that j is valid before continuing.
Here's your code with a few modifications to implement these safeguards and move the "magic number" 1000 to a #defined value.
#include <stdio.h>
#define FIBONACCI_LIMIT 1000L
int main(){
long i, j, fib[FIBONACCI_LIMIT];
fib[0] = 0;
fib[1] = 1;
if (scanf("%li", &j) != 1)
{
fprintf(stderr, "Invalid input\n");
return 1;
}
if (j<0 || j>=FIBONACCI_LIMIT)
{
fprintf(stderr, "Number must be in range 0 <= n < %li\n", FIBONACCI_LIMIT);
return 2;
}
for(i=2; i!=1000; i++)
{
fib[i] = (fib[i-2] + fib[i-1])%10;
}
printf("%li\n", fib[j]);
return 0;
}
The code can be improved by getting rid of the fib[] array altogether, since there is no need to store 1000 values when you only need to calculate one value. Furthermore, the final digits of numbers in the Fibonacci sequence form a repeating pattern of 60 values, so your first step should be to replace j with j % 60. Here is an improved version of the code that will work with any non-negative input capable of fitting into a long integer:
#include <stdio.h>
int main() {
long i, j, t, f0=0, f1=1;
if (scanf("%li", &j) != 1)
{
fprintf(stderr, "Invalid input\n");
return 1;
}
if (j < 0)
{
fprintf(stderr, "Number must be non-negative\n");
return 2;
}
j %= 60;
for (i=0; i<j; i++)
{
t = f0;
f0 = f1;
f1 = (f1 + t) % 10;
}
printf("%li\n", f0);
return 0;
}

You did not show what value of the variable j was entered.
Take into account that the next Fibonacci number is calculated incorrectly in the loop.
If to use the integer type unsigned long long then an object of this type can accommodate only 93 Fibonacci numbers.
The program can look like
#include <stdio.h>
#define N 100
int main(void)
{
while ( 1 )
{
unsigned long long fib[N] = { 0, 1 };
unsigned int n;
printf( "Enter a sequantial number of a fibonacci number (0 - exit): " );
if ( scanf("%u", &n) != 1 || n == 0 ) break;
unsigned int i = 2;
for (; i < N && i <= n && fib[i-1] <= fib[i-2] + fib[i-1]; i++)
{
fib[i] = fib[i - 2] + fib[i - 1];
}
if (n < i)
{
printf("#%u: %llu %llu\n", n, fib[n], fib[n] % 10);
}
else
{
puts("Too big fibonacci number");
}
}
return 0;
}
Its output might look like
Enter a sequantial number of a fibonacci number (0 - exit): 1
#1: 1 1
Enter a sequantial number of a fibonacci number (0 - exit): 2
#2: 1 1
Enter a sequantial number of a fibonacci number (0 - exit): 3
#3: 2 2
Enter a sequantial number of a fibonacci number (0 - exit): 93
#93: 12200160415121876738 8
Enter a sequantial number of a fibonacci number (0 - exit): 94
Too big fibonacci number
Enter a sequantial number of a fibonacci number (0 - exit): 0

Related

Write a program, which reads an Integer. Output another integer where the even digits are retained and odd digits are decremented by 1,

Here is my code:
#include <stdio.h>
#include <math.h>
int main() {
int num, i = 0, new_num = 0, u;
printf("Enter a number: ");
scanf("%d", &num);
while (num > 0) {
u = num % 10;
if (u % 2 == 0)
u = u;
if (u % 2 == 1)
u = u - 1;
new_num = new_num + u * pow(10, i);
num = num / 10;
i++;
}
printf("The new number is: %d", new_num);
return 0;
}
Now, when I am doing this in gcc(VS Code), for 2-digit number everything is ok. But for digits more than three I am getting a error. Like Input=23145 Output=22043. But I was expecting output=22044.
Also, if I run the same code in DevC/C++, there is no error.
Can anyone help me out in this?
Your program produces the expected output on my system: 22044 for 23145, but this might depend on the implementation of the pow function.
The reason you get a different output is probably a side effect of a precision issue with the pow() function in your C library: if pow(x, y) is implemented as exp(y * log(x)), the result for integral values of x and y could be very close but inferior to the actual integral value, causing the conversion to int to produce the previous integer. Some C library authors make a special case of integral arguments to avoid this problem, but it is highly recommended to avoid floating point functions for integer arithmetics to prevent such tricky issues.
I would advise some more changes in your code:
test the return value of scanf().
remove the if (u % 2 == 0) u = u; part, it has no effect.
in any case, there should be an else clause to not use the result of the previous case when testing for odd digits.
do not use the floating point function pow(): just keep a multiplier variable and update it in the loop.
the program does not handle negative numbers.
Here is a modified version:
#include <stdio.h>
int main() {
int num, new_num = 0, pow10 = 1;
printf("Enter a number: ");
if (scanf("%d", &num) != 1)
return 1;
while (num != 0) {
int digit = num % 10;
/* decrement odd digits absolute value */
digit -= digit % 2;
new_num = new_num + digit * pow10;
pow10 = pow10 * 10;
num = num / 10;
}
printf("The new number is: %d\n", new_num);
return 0;
}
Note that digit -= digit % 2; will decrement positive odd digits and actually increment negative odd digits, which effectively always decrements the absolute value of odd digits. This way both positive values and negative values are handled correctly.
In my instance of Visual Studio Code, for an input 23145, I indeed find 22044 as an output.
I guess the divergence comes with the cast of pow(10,i). Pow function in C returns a double which is not what you really want here. I strongly advice to not use the pow function for integer arithmetic.
A solution could be :
uint16_t i = 0u;
uint16_t current_digit = 0u, decimal_digit = 1u;
uint16_t new_number = 0u;
uint16_t number = 23145u;
while(number > 0u) {
current_digit = number % 10;
if (current_digit % 2) {
current_digit = current_digit - 1;
}
new_number = new_number + current_digit * decimal_digit;
decimal_digit *= 10u;
number /= 10;
i++;
}
printf("The new number is: %d", new_number);
It seems that the problem is using the function pow that returns a double value.
If you are dealing with integers then it is better to avoid using functions that return doubles due to a possible truncation then a double is converted to an integer.
Also pay attention to that the user can enter a negative number. Your program allows to do that. In this case your program also will produce an incorrect result.
I would write the program the following way
#include <stdio.h>
int main( void )
{
while (1)
{
const int Base = 10;
int num;
printf( "Enter a number (0 - exit): " );
if (scanf( "%d", &num ) != 1 || num == 0) break;
int new_num = 0;
for (int tmp = num, multiplier = 1; tmp != 0; tmp /= Base)
{
int digit = tmp % Base;
if (digit % 2 != 0)
{
digit += ( digit < 0 ? 1 : -1 );
}
new_num = new_num + multiplier * digit;
multiplier *= Base;
}
printf( "The original number is %d and the new number is: %d\n",
num, new_num );
putchar( '\n' );
}
}
The program output is
Enter a number (0 - exit): -123456789
The original number is -123456789 and the new number is: -22446688
Enter a number (0 - exit): 123456789
The original number is 123456789 and the new number is: 22446688
Enter a number (0 - exit): 0
If even for negative digits to add -1 then you should substitute this if statement
if (digit % 2 != 0)
{
digit += ( digit < 0 ? 1 : -1 );
}
for this one
if (digit % 2 != 0)
{
digit = ( digit -1 ) % Base;
}
In this case the program output might look like
Enter a number (0 - exit): -123456789
The original number is -123456789 and the new number is: -224466880
Enter a number (0 - exit): 123456789
The original number is 123456789 and the new number is: 22446688
Enter a number (0 - exit): 0
That is in this case the new value for the negative value -123456789 will be -224466880.

Armstrong number program in C returns wrong value

I am writing a program to see if a user entered number is Armstrong or not, here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
int x = 0;
printf("Enter a natural number: ");
scanf("%d", &x);
int ans = x;
// Digit Counter
int counter = 0; //Variable for number of digits in the user entered number
int b = x; //For each time number can be divided by 10 and isnt 0
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b != 0){
counter += 1;
}
}
++counter;
//Digit Counter
int sum = 0;
// Digit Finder
int D;
for (int j = 1; j <= x; j++){
D = x % 10; //Shows remainder of number (last digit) when divided by 10
sum += pow(D, counter); //Raises Digit found by counter and adds to sum
printf("%d\n", sum);
x /= 10; // Divides user entered number by 10 to get rid of digit found
}
if (sum == ans){
printf("%d is a Armstrong number! :)", ans);
}else
printf("%d is not an Armstrong number :(", ans);
//Digit Finder
return 0;
}
My problem is that the program works fine apart from one point, when the program is given a Armstrong number which does not start with 1 then it behaves normally and indicates if it is an Armstrong number or not, but when i input a Armstrong number which start with 1 then it will print out the Armstrong number but -1.
For example: If i input something such as 371 which is an Armstrong number it will show that it is an Armstrong number. However if i input 1634 it will output 1633 which is 1 less than 1634.
How can i fix this problem?, also by the way could someone comment on my code and tell me if it seems good and professional/efficient because i am a beginner in C and would like someone else's opinion on my code.
How can I fix this problem.
You know the number of iterations you want to make once you have calculated the digit count. So instead of looping till you reach the value of x:
for (int j = 1; j <= x; j++){
use the digit counter instead:
for (int j = 1; j <= counter; j++) {
also by the way could someone comment on my code and tell me if it seems good and professional/efficient because i am a beginner in C and would like someone else's opinion on my code.
There's a number of things you can do to improve your code.
First and foremost, any piece of code should be properly indented and formatted. Right now your code has no indenting, which makes it more difficult to read and it just looks ugly in general. So, always indent your code properly. Use an IDE or a good text editor, it will help you.
Be consistent in your code style. If you are writing
if (some_cond) {
...
}
else
//do this
It is not consistent. Wrap the else in braces as well.
Always check the return value of a function you use, especially for scanf. It will save you from many bugs in the future.
if (scanf("%d", &x) == 1)
//...all OK...
else
// ...EOF or conversion failure...
exit(EXIT_FAILURE);
Your first for loop will iterate x times uselessly. You can stop when you know that you have hit 0:
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b == 0){
break;
}
counter += 1;
}
C has ++ operator. Use that instead of doing counter += 1
int D; you create this, but don't initialize it. Always initialize your variables as soon as possible
C has const qualifier keyword, which makes a value immutable. This makes your code more readable, as the reader can immediately tell that this value will not change. In your code, you can change ans variable and make it a const int because it never changes:
const int ans = x;
Use more descriptive names for your variables. ans, D don't tell me anything. Use proper names, so that the reader of your code can easily understand your code.
These are some of the things that in my opinion you should do and keep doing to improve your code and coding skills. I am sure there can be more things though. Keep your code readable and as simple as possible.
The condition in this loop
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b != 0){
counter += 1;
}
}
does not make sense because there will be numerous redundant iterations of the loop.
For example if x is equal to 153 that is contains only 3 digits the loop will iterate exactly 153 times.
Also additional increment of the variable counter after the loop
++counter;
makes the code logically inconsistent.
Instead of the loop you could write at least the following way
int counter = 0;
int b = x;
do
{
++counter;
} while ( b /= 10 );
This loop iterates exactly the number of times equal to the number of digits in a given number.
In this loop
for (int j = 1; j <= x; j++){
D = x % 10; //Shows remainder of number (last digit) when divided by 10
sum += pow(D, counter); //Raises Digit found by counter and adds to sum
printf("%d\n", sum);
x /= 10; // Divides user entered number by 10 to get rid of digit found
}
it seems you did not take into account that the variable x is decreased inside the body of the loop
x /= 10; // Divides user entered number by 10 to get rid of digit found
So the loop can interrupt its iterations too early. In any case the condition of the loop again does not make great sense the same way as the condition of the first loop and only adds a bug.
The type of used variables that store a given number should be unsigned integer type. Otherwise the user can enter a negative number.
You could write a separate function that checks whether a given number is an Armstrong number.
Here you are.
#include <stdio.h>
int is_armstrong( unsigned int x )
{
const unsigned int Base = 10;
size_t n = 0;
unsigned int tmp = x;
do
{
++n;
} while ( tmp /= Base );
unsigned int sum = 0;
tmp = x;
do
{
unsigned int digit = tmp % Base;
unsigned int power = digit;
for ( size_t i = 1; i < n; i++ ) power *= digit;
sum += power;
} while ( ( tmp /= Base ) != 0 && !( x < sum ) );
return tmp == 0 && x == sum;
}
int main(void)
{
unsigned int a[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407,
1634, 8208, 9474, 54748, 92727, 93084, 548834
};
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++ )
{
printf( "%u is %san Armstrong number.\n", a[i], is_armstrong( a[i] ) ? "": "not " );
}
return 0;
}
The program output is
0 is an Armstrong number.
1 is an Armstrong number.
2 is an Armstrong number.
3 is an Armstrong number.
4 is an Armstrong number.
5 is an Armstrong number.
6 is an Armstrong number.
7 is an Armstrong number.
8 is an Armstrong number.
9 is an Armstrong number.
153 is an Armstrong number.
370 is an Armstrong number.
371 is an Armstrong number.
407 is an Armstrong number.
1634 is an Armstrong number.
8208 is an Armstrong number.
9474 is an Armstrong number.
54748 is an Armstrong number.
92727 is an Armstrong number.
93084 is an Armstrong number.
548834 is an Armstrong number.
Please remove j++ from 2nd loop for (int j = 1; j <= x; j++)
I tried this:
void armstrong(int x)
{
// count digits
int counter = 0, temp = x, sum = 0;
while(temp != 0)
{
temp = temp/10;
++counter; // Note: pre increment faster
}
// printf("count %d\n",counter);
temp = x;
while(temp != 0)
{
sum += pow(temp % 10, counter);
temp = temp/10;
}
// printf("sum %d\n",sum);
if(x == sum)
{
printf("Armstrong\n");
}
else
{
printf("No Armstrong\n");
}
}
int main(){
armstrong(371);
armstrong(1634);
return 0;
}
Let's take this and add the ability to handle multiple numeric bases while we're at it. Why? BECAUSE WE CAN!!!! :-)
#include <stdio.h>
#include <math.h>
double log_base(int b, double n)
{
return log(n) / log((double)b);
}
int is_armstrong_number(int b, /* base */
int n)
{
int num_digits = trunc(log_base(b, (double)n)) + 1;
int sum = 0;
int remainder = n;
while(remainder > 0)
{
sum = sum + pow(remainder % b, num_digits);
remainder = (int) (remainder / b);
}
return sum == n;
}
int main()
{
printf("All the following are valid Armstrong numbers\n");
printf(" 407 base 10 - result = %d\n", is_armstrong_number(10, 407));
printf(" 0xEA1 base 16 - result = %d\n", is_armstrong_number(16, 0xEA1));
printf(" 371 base 10 - result = %d\n", is_armstrong_number(10, 371));
printf(" 1634 base 10 - result = %d\n", is_armstrong_number(10, 1634));
printf(" 0463 base 8 - result = %d\n", is_armstrong_number(8, 0463));
printf("All the following are NOT valid Armstrong numbers\n");
printf(" 123 base 10 - result = %d\n", is_armstrong_number(10, 123));
printf(" 0x2446 base 16 - result = %d\n", is_armstrong_number(16, 0x2446));
printf(" 022222 base 8 - result = %d\n", is_armstrong_number(8, 022222));
}
At the start of is_armstrong_number we compute the number of digits directly instead of looping through the number. We then loop through the digits of n in base b, summing up the value of the digit raised to the number of digits in the number, for the given numeric base. Once the remainder hits zero we know there are no more digits to compute and we return a flag indicating if the given number is an Armstrong number in the given base.

Validating card credit numbers

I've been trying to create a program that can check if a credit card number is valid or not based on Hans Peter Luhn's algorithm. However, I can only get it to work for some inputs.
// Loop through every digit in the card number
for ( int i = 0; i < intlen (num); ++i )
{
nextDigit = getDigit (num, i);
// If every other number...
if ( i % 2 )
{
nextDigit *= 2;
// ...times by two and add the individual digits to the total
for ( int j = 0; j < intlen (nextDigit); ++j )
{
total += getDigit (nextDigit, j);
}
}
else
{
total += nextDigit;
}
}
When I use the AMEX card number 378282246310005 it works fine and tells the user it's valid. However, once I try the VISA card number 4012888888881881 it says it's invalid. I tried to do a sanity check and do it manually to see if my program was wrong but I deduced the same result. These card number were taken from the Paypal test credit card numbers page so I know they are valid.
So what am I doing wrong?
To clarify the details by the program, if total modulo 10 == 0 then the card number is valid.
Functions called:
// Function to return length (number of digits) of an int
int intlen (long long n)
{
int len = 1;
// While there is more than 1 digit...
while ( abs (n) > 9 )
{
// ...discard leading digits and add 1 to len
n /= 10;
++len;
}
return len;
}
// Function to return a digit in an integer at a specified index
short getDigit (long long num, int index)
{
// Calculating position of digit in integer
int pos = intlen (num) - index;
// Discard numbers after selected digit
while ( pos > 1 )
{
num /= 10;
--pos;
}
// Return right-most digit i.e. selected digit
return num % 10;
}
You'll want to change i % 2 to i % 2 == intlen (num) % 2 or similar; you should double every second digit, but starting from the right; i.e. excluding the final check digit:
From the rightmost digit, which is the check digit, moving left, double the value of every second digit; …
The reason the AMEX number you tried validated anyway is because it's an odd number of digits; the same digits get doubled regardless of whether you skip from the front or the back.
While I was looking at this to find the bug, I re-wrote the program to make it a bit simpler. As a side-effect this will be much faster.
We need to grab digits from the right anyway. We don't even need to count the digits; just keep pulling off the right-most digit until the number becomes 0. If the number starts out as 0, the checksum is trivially 0 and the code is still correct.
I grabbed all the numbers from the test page. This seems to be correct, except for one number: 76009244561 (listed as "Dankort (PBS)" in the test page). I tried this number with the Python code from the Wikipedia page, and again this number is rejected. I don't know why this number is different from the others.
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
bool check_one(long long num)
{
int checksum = 0;
int i = 1;
for (int i = 1; num; num /= 10, ++i)
{
int d = num % 10;
if (i % 2 == 0)
{
// even digit: double and add digits of doubled value
d *= 2;
if (d < 10)
{
// only one digit: we doubled a 0-4 so number is 0-8
checksum += d;
}
else
{
// two digits: we doubled a 5-9 so number is 10-18
checksum += (d % 10);
checksum += (d / 10);
}
}
else
{
// odd digit: just add
checksum += d;
}
}
return (checksum % 10) == 0;
}
static long long const valid_nums[] =
{
378282246310005,
371449635398431,
378734493671000,
5610591081018250,
30569309025904,
38520000023237,
6011111111111117,
6011000990139424,
3530111333300000,
3566002020360505,
5555555555554444,
5105105105105100,
4111111111111111,
4012888888881881,
4222222222222,
76009244561,
5019717010103742,
6331101999990016,
};
static size_t len_valid_nums = sizeof(valid_nums) / sizeof(valid_nums[0]);
static long long const non_valid_nums[] =
{
378282246310006, // add 1 to valid
371449635398432,
378734493671001,
5610591081018205, // swap last two digits
30569309025940,
38520000023273,
601111111111111, // delete last digit
601100099013942,
353011133330000,
};
static size_t len_non_valid_nums =
(sizeof(non_valid_nums) / sizeof(non_valid_nums[0]));
main()
{
bool f;
for (int i = 0; i < len_valid_nums; ++i)
{
long long num = valid_nums[i];
f = check_one(num);
if (!f)
{
printf("Number %lld considered invalid but should be valid\n", num);
}
}
for (int i = 0; i < len_non_valid_nums; ++i)
{
long long num = non_valid_nums[i];
f = check_one(num);
if (f)
{
printf("Number %lld considered valid but should be invalid\n", num);
}
}
}

Extracting individual digits from a long in C

I'm doing a homework assignment for my course in C (first programming course).
Part of the assignment is to write code so that a user inputs a number up to 9 digits long, and the program needs to determine whether this number is "increasing"/"truly increasing"/"decreasing"/"truly decreasing"/"increasing and decreasing"/"truly decreasing and truly increasing"/"not decreasing and not increasing". (7 options in total)
Since this is our first assignment we're not allowed to use anything besides what was taught in class:
do-while, for, while loops, else-if, if,
break,continue
scanf, printf ,modulo, and the basic operators
(We can't use any library besides for stdio.h)
That's it. I can't use arrays or getchar or any of that stuff. The only function I can use to receive input from the user is scanf.
So far I've already written the algorithm with a flowchart and everything, but I need to separate the user's input into it's distinct digits.
For example, if the user inputs "1234..." i want to save 1 in a, 2 in b, and so on, and then make comparisons between all the digits to determine for example whether they are all equal (increasing and decreasing) or whether a > b >c ... (decreasing) and so on.
I know how to separate each digit by using the % and / operator, but I can't figure out how to "save" these values in a variable that I can later use for the comparisons.
This is what I have so far:
printf("Enter a positive number : ");
do {
scanf ("%ld", &number);
if (number < 0) {
printf ("invalid input...enter a positive integer: ");
continue;
}
else break;
} while (1);
while (number < 0) {
a = number % 10;
number = number - a;
number = number / 10;
b = a;
}
Why not scan them as characters (string)? Then you can access them via an array offset, by subtracting the offset of 48 from the ASCII character code. You can verify that the character is a digit using isdigit from ctype.h.
EDIT
Because of the incredibly absent-minded limitations that your professor put in place:
#include <stdio.h>
int main()
{
int number;
printf("Enter a positive number: ");
do
{
scanf ("%ld", &number);
if (number < 0)
{
printf ("invalid input...enter a positive integer: ");
continue;
}
else break;
} while (1);
int a = -1;
int b = -1;
int c = -1;
int d = -1;
int e = -1;
int f = -1;
int g = -1;
int h = -1;
int i = -1;
while (number > 0)
{
if (a < 0) a = number % 10;
else if (b < 0) b = number % 10;
else if (c < 0) c = number % 10;
else if (d < 0) d = number % 10;
else if (e < 0) e = number % 10;
else if (f < 0) f = number % 10;
else if (g < 0) g = number % 10;
else if (h < 0) h = number % 10;
else if (i < 0) i = number % 10;
number /= 10;
}
/* Printing for verification. */
printf("%i", a);
printf("%i", b);
printf("%i", c);
printf("%i", d);
printf("%i", e);
printf("%i", f);
printf("%i", g);
printf("%i", h);
printf("%i", i);
return 0;
}
The valid numbers at the end will be positive, so those are the ones you validate to meet your different conditions.
Since you only need to compare consecutive digits, there is an elegant way to do this without arrays:
int decreasing = 2;
int increasing = 2;
while(number > 9)
{
int a = number % 10;
int b = (number / 10) % 10;
if(a == b)
{
decreasing = min(1, decreasing);
increasing = min(1, increasing);
}
else if(a > b)
decreasing = 0;
else if(a < b)
increasing = 0;
number /= 10;
}
Here, we walk through the number (by dividing by 10) until only one digit remains. We store info about the number up to this point in decreasing and increasing - a 2 means truly increasing/decreasing, a 1 means increasing/decreasing, and a 0 means not increasing/decreasing.
At each step, a is the ones digit and b is the tens. Then, we change increasing and decreasing based on a comparison between a and b.
At the end, it should be easy to turn the values of increasing and decreasing into the final answer you want.
Note: The function min returns the smaller of its 2 arguments. You should be able to write your own, or replace those lines with if statements or conditionals.
It's stupid to ask you to do loops without arrays --- but that's your teacher's fault, not yours.
That being said, I would do something like this:
char c;
while (1) {
scanf("%c", &c);
if (c == '\n') /* encountered newline (end of input) */
break;
if (c < '0' || c > '9')
break; /* do something to handle bad characters? */
c -= '0';
/*
* At this point you've got 0 <= c < 9. This is
* where you do your homework :)
*/
}
The trick here is that when you type numbers into a program, you send the buffer all at once, not one character at a time. That means the first scanf will block until the entire string (i.e. "123823" or whatever) arrives all at once, along with the newline character ( '\n' ). Then this loop parses that string at its leisure.
Edit For testing the increasing/decreasing-ness of the digits, you may think you need to store the entire string, but that's not true. Just define some additional variables to remember the important information, such as:
int largest_digit_ive_seen, smallest_digit_ive_seen, strict_increasing_thus_far;
etc. etc.
Let us suppose you have this number 23654
23654 % 10000 = 2 and 3654
3654 % 1000 = 3 and 654
654 % 100 = 6 and 54
54 % 10 = 5 and 4
4
This way you can get all the digits. Of course, you have to know if the number is greater than 10000, 1000, 100 or 10, in order to know the first divisor.
Play with sizeof to get the size of the integer, in order to avoid a huge if...else statement
EDIT:
Let us see
if (number>0) {
// Well, whe have the first and only digit
} else if (number>10) {
int first_digit = number/10;
int second_digit = number % 10;
} else if (number>100) {
int first_digit = number/100;
int second_digit = (number % 100)/10;
int third_digit = (number % 100) % 10;
} ...
and so on, I suppose
// u_i is the user input, My homework asked me to extract a long long, however, this should also be effective for a long.
int digits = 0;
long long d_base = 1;
int d_arr[20];
while (u_i / d_base > 0)
{
d_arr[digits] = (u_i - u_i / (d_base * 10) * (d_base * 10)) / d_base;
u_i -= d_arr[digits] * d_base;
d_base *= 10;
digits++;
}
EDIT: the extracted individual digit now lives in the int array d_arr. I'm not good at C, so I think the array declaration can be optimized.
Here's a working example in plain C :
#include <stdio.h>
unsigned long alePow (unsigned long int x, unsigned long int y);
int main( int argc, const char* argv[] )
{
int enter_num, temp_num, sum = 0;
int divisor, digit, count = 0;
printf("Please enter number\n");
scanf("%d", &enter_num);
temp_num = enter_num;
// Counting the number of digits in the entered integer
while (temp_num != 0)
{
temp_num = temp_num/10;
count++;
}
temp_num = enter_num;
// Extracting the digits
printf("Individual digits in the entered number are ");
do
{
divisor = (int)(alePow(10.0, --count));
digit = temp_num / divisor;
temp_num = temp_num % divisor;
printf(" %d",digit);
sum = sum + digit;
}
while(count != 0);
printf("\nSum of the digits is = %d\n",sum);
return 0;
}
unsigned long alePow(unsigned long int x, unsigned long int y) {
if (x==0) { return 0; }
if (y==0||x==1) { return 1; }
if (y==1) { return x; }
return alePow(x*x, y/2) * ((y%2==0) ? 1 : x);
}
I would suggest loop-unrolling.
int a=-1, b=-1, c=-1, d=-1, e=1, f=-1, g=-1, h=-1, i=-1; // for holding 9 digits
int count = 0; //for number of digits in the given number
if(number>0) {
i=number%10;
number/=10;
count++;
}
if(number>0) {
h=number%10;
number/=10;
count++;
}
if(number>0) {
g=number%10;
number/=10;
count++;
}
....
....
/* All the way down to the storing variable a */
Now, you know the number of digits (variable count) and they are stored in which of the variables. Now you have all digits and you can check their "decreasing", "increasing" etc with lots of if's !
I can't really think of a better soltion given all your conditions.

Finding largest prime factor of a composite number in c

I am accepting a composite number as an input. I want to print all its factors and also the largest prime factor of that number. I have written the following code. It is working perfectly ok till the number 51. But if any number greater than 51 is inputted, wrong output is shown. how can I correct my code?
#include<stdio.h>
void main()
{
int i, j, b=2, c;
printf("\nEnter a composite number: ");
scanf("%d", &c);
printf("Factors: ");
for(i=1; i<=c/2; i++)
{
if(c%i==0)
{
printf("%d ", i);
for(j=1; j<=i; j++)
{
if(i%j > 0)
{
b = i;
}
if(b%3==0)
b = 3;
else if(b%2==0)
b = 2;
else if(b%5==0)
b = 5;
}
}
}
printf("%d\nLargest prime factor: %d\n", c, b);
}
This is a bit of a spoiler, so if you want to solve this yourself, don't read this yet :). I'll try to provide hints in order of succession, so you can read each hint in order, and if you need more hints, move to the next hint, etc.
Hint #1:
If divisor is a divisor of n, then n / divisor is also a divisor of n. For example, 100 / 2 = 50 with remainder 0, so 2 is a divisor of 100. But this also means that 50 is a divisor of 100.
Hint #2
Given Hint #1, what this means is that we can loop from i = 2 to i*i <= n when checking for prime factors. For example, if we are checking the number 100, then we only have to loop to 10 (10*10 is <= 100) because by using hint #1, we will get all the factors. That is:
100 / 2 = 50, so 2 and 50 are factors
100 / 5 = 20, so 5 and 20 are factors
100 / 10 = 10, so 10 is a factor
Hint #3
Since we only care about prime factors for n, it's sufficient to just find the first factor of n, call it divisor, and then we can recursively find the other factors for n / divisor. We can use a sieve approach and mark off the factors as we find them.
Hint #4
Sample solution in C:
bool factors[100000];
void getprimefactors(int n) {
// 0 and 1 are not prime
if (n == 0 || n == 1) return;
// find smallest number >= 2 that is a divisor of n (it will be a prime number)
int divisor = 0;
for(int i = 2; i*i <= n; ++i) {
if (n % i == 0) {
divisor = i;
break;
}
}
if (divisor == 0) {
// we didn't find a divisor, so n is prime
factors[n] = true;
return;
}
// we found a divisor
factors[divisor] = true;
getprimefactors(n / divisor);
}
int main() {
memset(factors,false,sizeof factors);
int f = 1234;
getprimefactors(f);
int largest;
printf("prime factors for %d:\n",f);
for(int i = 2; i <= f/2; ++i) {
if (factors[i]) {
printf("%d\n",i);
largest = i;
}
}
printf("largest prime factor is %d\n",largest);
return 0;
}
Output:
---------- Capture Output ----------
> "c:\windows\system32\cmd.exe" /c c:\temp\temp.exe
prime factors for 1234:
2
617
largest prime factor is 617
> Terminated with exit code 0.
I presume you're doing this to learn, so I hope you don't mind a hint.
I'd start by stepping through your algorithm on a number that fails. Does this show you where the error is?
You need to recode so that your code finds all the prime numbers of a given number, instead of just calculating for the prime numbers 2,3, and 5. In other words, your code can only work with the number you are calculating is a prime number or is a multiple of 2, 3, or 5. But 7, 11, 13, 17, 19 are also prime numbers--so your code should simply work by finding all factors of a particular number and return the largest factor that is not further divisible.
Really, this is very slow for all but the smallest numbers (below, say, 100,000). Try finding just the prime factors of the number:
#include <cmath>
void addfactor(int n) {
printf ("%d\n", n);
}
int main()
{
int d;
int s;
int c = 1234567;
while (!(c&1)) {
addfactor(2);
c >>= 1;
}
while (c%3 == 0) {
addfactor(3);
c /= 3;
}
s = (int)sqrt(c + 0.5);
for (d = 5; d <= s;) {
while (c % d == 0) {
addfactor(d);
c /= d;
s = (int)sqrt(c + 0.5);
}
d += 2;
while (c % d == 0) {
addfactor(d);
c /= d;
s = (int)sqrt(c + 0.5);
}
d += 4;
}
if (c > 1)
addfactor(c);
return 0;
}
where addfactor is some kind of macro that adds the factor to a list of prime factors. Once you have these, you can construct a list of all the factors of the number.
This is dramatically faster than the other code snippets posted here. For a random input like 10597959011, my code would take something like 2000 bit operations plus 1000 more to re-constitute the divisors, while the others would take billions of operations. It's the difference between 'instant' and a minute in that case.
Simplification to dcp's answer(in an iterative way):
#include <stdio.h>
void factorize_and_print(unsigned long number) {
unsigned long factor;
for(factor = 2; number > 1; factor++) {
while(number % factor == 0) {
number = number / factor;
printf("%lu\n",factor);
}
}
}
/* example main */
int main(int argc,char** argv) {
if(argc >= 2) {
long number = atol(argv[1]);
factorize_and_print(number);
} else {
printf("Usage: %s <number>%<number> is unsigned long", argv[0]);
}
}
Note: There is a number parsing bug here that is not getting the number in argv correctly.

Resources