Why does this recursive code throw a segfault? - c

When I run the following code compiled with with gcc (only option turned on is -std=c99) and run the executable, I get a segmentation fault (msg core dumped).
Why is that?
#include <stdio.h>
int count_factors(int n, int i) {
int m = n;
if (m == i) {
return 1;
} else if (m % i == 0) {
while (m % i == 0) m = m / i;
return 1 + count_factors(m, i);
} else {
return count_factors(m, i+1);
}
}
int main() {
int streak_size = 4;
int streak = 0;
int solution = 0;
int n = 2;
while (solution == 0) {
n += 1;
int c = count_factors(n, 2);
if (c == streak_size) {
streak += 1;
} else {
streak = 0;
}
if (streak == streak_size) solution = n;
}
printf("%i", solution);
return 0;
}

In your recursion, there's one base case you're considering. However, there are two:
m == i: This occurs when there is only 1 of the largest factor
m == 1: This happens when there are multiple of the largest factor
You're going into an infinite loop on m=4 and n=2 because you're missing the second case. Here, if (m % i == 0) is true, so while (m % i == 0) m = m / i; runs. And since 4 is a multiple of 2, this loop will end when m is 1.
When you recurse again, you have m=1 and n=2. This will hit the else clause, where you call count_factors again with m=1 and n=3. This keeps going until the stack blows up.
Adding the second base case will fix the infinite recursion:
int count_factors(int n, int i) {
int m = n;
if (m == i) {
return 1;
} else if (m == 1) {
return 0;
} else if (m % i == 0) {
while (m % i == 0) m = m / i;
return 1 + count_factors(m, i);
} else {
return count_factors(m, i+1);
}
}
Actually, you can get rid of the first case, since it's just a special case of if (m % i == 0):
int count_factors(int n, int i) {
int m = n;
if (m == 1) {
return 0;
} else if (m % i == 0) {
while (m % i == 0) m = m / i;
return 1 + count_factors(m, i);
} else {
return count_factors(m, i+1);
}
}
The program then runs to completion, outputting 134046.
EDIT:
It will run faster without recursion:
int count_factors(int n, int i) {
int m = n;
int total = 0;
while (m != 1) {
if (m % i == 0) {
while (m % i == 0) m = m / i;
total++;
}
i++;
}
return total;
}
On my machine, the recursive version takes about 9 seconds. The iterative version takes about 3 seconds.

Related

Why does my program only work half the time?

I have an assignment to write a program for a natural number where its inverse is divisible by its number of digits. A natural number n ( n > 9) is entered from the keyboard. To find and print the largest natural number less than n that its inverse is divisible by its number of digits. If the entered number is not valid, print a corresponding message (Brojot ne e validen).
I have tried :
#include <stdio.h>
int main() {
int n,r,s=0,a=0;
int m;
scanf("%d",&n);
int t=n;
if(t<10)
{ printf("Brojot ne e validen");}
else {
for (int i = n - 1; i > 0; i--) {
while (n != 0) {
r = n % 10;
s = (s * 10) + r;
n = n / 10;
a++;
if (s % a == 0) {
m = i;
break;
}
}
}
printf("%d\n", m);
}
return 0;
}
And when my inputs is 50, it gives the correct answer which is 49, but when I try numbers like 100 or 17 it prints 98 instead of 89 and 16 instead of 7 respectively. I have been baffled by this for more than an hour now
check your logic.
you can check each value by
#include <stdio.h>
int main() {
int t,r,s=0,a=0;
int m;
scanf("%d",&t);
if(t<10)
{ printf("Brojot ne e validen");}
else {
for (int i = t - 1; i > 0; i--) {
while (t != 0) {
r = t % 10;
printf("%d \n", r);
s = (s * 10) + r;
printf("%d \n", s);
t = t / 10;
printf("%d \n", t);
a++;
if (s % a == 0) {
m = i;
break;
}
}
}
printf("%d\n", m);
}
return 0;
}

Find all the decomposition of a number using only odd numbers and up to N numbers max

I want to find all the decompositions of a number using only odd numbers and up to N numbers max.
For example for the number 7 and N = 3, I can only get 1+1+5, 1+3+3, 7. I can't get 1+1+1+1+3 because it's greater then N.
They hint us to use backtracking.
I strated writing the code and I am stuck. If someone can explian to me how to solve this problem it will be great.
int T(int n, int k)
{
if (k == 0)
{
return;
}
int arr[N];
int f;
for (f = 0; f < N; f++)
{
arr[f] = 0;
}
int sum = 0;
int j = 1;
int i = 1;
int c = 0;
while (j < k) {
sum = sum + i;
arr[c] = i;
if (sum == n)
{
for (f = 0; f < N; f++)
{
if (arr[f] != 0)
{
printf("%d ", arr[f]);
}
}
printf("\n");
}
else if (sum > n)
{
arr[c] = 0;
sum = sum - i;
i = i - 2;
}
else
{
i = i + 2;
j++;
c++;
}
}
T(n, k - 1);
}
Please compile with warnings (-Wall) and fix all of them (-Werror helps make sure you do this). I didn't build your code, but int T(int n, int k) says it returns an int, yet the function code is void.
With backtracking, you can't print at each node because the current node in the graph might not actually lead to a solution. It's premature to commit anything to the result set until you actually reach it.
It's best not to print in functions that perform logical tasks anyway, but it can make the coding easier while developing the logic so I'll stick wiith it.
The backtracking suggestion is a good one. Here's the logic:
The "found result" base case is when n == 0 && k >= 0, if you're decrementing n and k and using them to represent the remaining value to reach the goal and the number of choices left. If you're incrementing variables to count up to n and k, that's fine too, in which case the base case is current_total == n && taken_so_far <= k.
Next, the "failure" base case is k < 0 || n < 0 because we've either overshot n or run out of numbers to take.
After that, the recursive case is, in English, "try taking each odd number i up to n, recursing on the possibility that i might be part of the solution". Per your spec, we don't accept any sequence of descending numbers which prunes the recursion tree a bit.
Here's the code; again, returning a result is an exercise. I'm using a k-sized array to store potential results, then dumping it to stdout only when a result was found.
#include <stdio.h>
#include <stdlib.h>
void odd_decomposition_search(
int n, const int k, int taken_length, int *taken
) {
if (n == 0 && taken_length <= k && taken_length > 0) {
for (int i = 0; i < taken_length - 1; i++) {
printf("%d+", taken[i]);
}
printf("%d\n", taken[taken_length-1]);
}
else if (n > 0 && taken_length < k) {
int i = taken_length ? taken[taken_length-1] : 1;
for (; i <= n; i += 2) {
taken[taken_length] = i;
odd_decomposition_search(n - i, k, taken_length + 1, taken);
}
}
}
void odd_decomposition(const int n, const int k) {
if (n <= 0 || k <= 0) {
return;
}
int taken[k];
odd_decomposition_search(n, k, 0, taken);
}
int main() {
int n = 7;
int k = 3;
odd_decomposition(n, k);
return 0;
}
If you're having trouble understanding the call stack, here's a visualizer you can run in the browser:
const oddDecomp = (n, k, taken=[]) => {
console.log(" ".repeat(taken.length), `[${taken}]`);
if (n === 0 && taken.length <= k && taken.length) {
console.log(" ".repeat(taken.length), "-> found result:", taken.join("+"));
}
else if (n > 0 && taken.length < k) {
for (let i = taken.length ? taken[taken.length-1] : 1; i <= n; i += 2) {
taken.push(i);
oddDecomp(n - i, k, taken);
taken.pop(i);
}
}
};
oddDecomp(7, 3);

How to find the nearest prime for a given number using for loop in C?

I really tried but still don't know what's wrong with my code.
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
int minus, i, judge;
for (minus = 0, judge = 1; judge == 1; minus++, n -= minus) {
for (i = 2; i * i < n; i++) {
if (n % i == 0)
judge = 1;
else judge = 0;
}
if (judge == 1)
continue;
else break;
}
printf("%d\n", n);
return 0;
}
When I input 143, the output is 143 not 139.
However, when I input 11, the output is the correct answer 11.
The loop test is incorrect: for (i = 2; i * i < n; i++)
If n is the square of a prime number, the loop will stop just before finding the factor.
You should either use i * i <= n or i <= n / i.
Furthermore, you do not enumerate all numbers as you decrement n by an increasing value at each iteration.
Note also that the loop would not find the closest prime to n, but the greatest prime smaller than n, which is not exactly the same thing.
Here is a modified version:
#include <limits.h>
#include <stdio.h>
int isPrime(int n) {
if (n <= 2 || n % 2 == 0)
return n == 2;
for (int i = 3; i <= n / i; i += 2) {
if (n % i == 0)
return 0;
}
return 1;
}
int main() {
int n;
if (scanf("%d", &n) != 1)
return 1;
if (n <= 2) {
printf("2\n");
} else {
for (i = 0;; i++) {
if (isPrime(n - i))
printf("%d\n", n - i);
break;
}
if (n <= INT_MAX - i && isPrime(n + i))
printf("%d\n", n + i);
break;
}
}
}
return 0;
}

Finding the numbers that are palindromic in both base 2 and 10 and summing them up

I need to find the sum of all numbers that are less or equal with my input number (it requires them to be palindromic in both radix 10 and 2). Here is my code:
#include <stdio.h>
#include <stdlib.h>
int pal10(int n) {
int reverse, x;
x = n;
while (n != 0) {
reverse = reverse * 10 + n % 10;
n = n / 10;
}
if (reverse == x)
return 1;
else
return 0;
}
int length(int n) {
int l = 0;
while (n != 0) {
n = n / 2;
l++;
}
return l;
}
int binarypal(int n) {
int v[length(n)], i = 0, j = length(n);
while (n != 0) {
v[i] = n % 2;
n = n / 2;
i++;
}
for (i = 0; i <= length(n); i++) {
if (v[i] == v[j]) {
j--;
} else {
break;
return 0;
}
}
return 1;
}
int main() {
long s = 0;
int n;
printf("Input your number \n");
scanf("%d", &n);
while (n != 0) {
if (binarypal(n) == 1 && pal10(n) == 1)
s = s + n;
n--;
}
printf("Your sum is %ld", s);
return 0;
}
It always returns 0. My guess is I've done something wrong in the binarypal function. What should I do?
You have multiple problems:
function pal10() fails because reverse is not initialized.
function binarypal() is too complicated, you should use the same method as pal10().
you should avoid comparing boolean function return values with 1, the convention in C is to return 0 for false and non zero for true.
you should avoid using l for a variable name as it looks very similar to 1 on most constant width fonts. As a matter of fact, it is the same glyph for the original Courier typewriter font.
Here is a simplified and corrected version with a multi-base function:
#include <stdio.h>
#include <stdlib.h>
int ispal(int n, int base) {
int reverse = 0, x = n;
while (n > 0) {
reverse = reverse * base + n % base;
n = n / base;
}
return reverse == x;
}
int main(void) {
long s = 0;
int n = 0;
printf("Input your number:\n");
scanf("%d", &n);
while (n > 0) {
if (ispal(n, 10) && ispal(n, 2))
s += n;
n--;
}
printf("Your sum is %ld\n", s);
return 0;
}
in the function pal10 the variable reverse is not initialized.
int pal10(int n)
{
int reverse,x;
^^^^^^^
x=n;
while(n!=0)
{
reverse=reverse*10+n%10;
n=n/10;
}
if(reverse==x)
return 1;
else
return 0;
}
In the function binarypal this loop is incorrect because the valid range of indices of an array with length( n ) elements is [0, length( n ) - 1 ]
for(i=0;i<=length(n);i++)
{
if(v[i]==v[j])
{
j--;
}
else
{
break;
return 0;
}
}
And as #BLUEPIXY pointed out you shall remove the break statement from this else
else
{
break;
return 0;
}

Help making this code run faster for SPOJ

I've been doing a few of the challenges on the Sphere Online Judge (SPOJ), but I can't seem to get the second problem (the prime generator) to run within the time limit. How can the speed of the following code be increased?
#include <stdio.h>
#include <math.h>
int is_prime(int n);
void make_sieve();
void fast_prime(int n);
int primes[16000];
int main()
{
int nlines;
int m, n;
make_sieve();
scanf("%d", &nlines);
for (; nlines >= 1; nlines--) {
scanf("%d %d", &m, &n);
if (!(m % 2)) {
m++;
}
for ( ; m < n; m+=2) {
fast_prime(m);
}
printf("\n");
}
return 0;
}
/* Prints a number if it's prime. */
inline void fast_prime(int n)
{
int j;
for (int i = 0; ((j = primes[i]) > -1); i++) {
if (!(n % j)) {
return;
}
}
printf("%d\n", n);
}
/* Create an array listing prime numbers. */
void make_sieve()
{
int j = 0;
for (int i = 0; i < 16000; i++) {
primes[i] = -1;
}
for (int i = 2; i < 32000; i++) {
if (i % 2) {
if (is_prime(i)) {
primes[j] = i;
j++;
}
}
}
return;
}
/* Test if a number is prime. Return 1 if prime. Return 0 if not. */
int is_prime(int n)
{
int rootofn;
rootofn = sqrt(n);
if ((n <= 2) || (n == 3) || (n == 5) || (n == 7)) {
return 1;
}
if (((n % 2) == 0) || ((n % 3) == 0) || ((n % 5) == 0) || ((n % 7) == 0)) {
return 0;
}
for (int i = 11; i < rootofn; i += 2) {
if ((n % i) == 0) {
return 0;
}
}
return 1;
}
isprime() does not make use of the prime number table primes[].
Plus, implement a search of the primes array that will complete quickly using a binary search algorithm. The standard library has one.
To see where your time is spent in code you can use profiling
gcc example
gcc -p -g - o mycode mycode.c
===run the code--
gprof mycode
Currently, your problem isn't time limit. Its the fact that your program never print any numbers.
The most obvious error is that in fast_prime you are checking if n is divisible by prime[0], prime[1],... up to prime[k]. Even if n is prime, you won't print it, because n is somewhere in primes[], and so you'll get that n is divisible by some number...
To correct this, you need to check that n is divisible by some prime number up to the square root of n (this will also have the side effect of speeding up the code, as less numbers will be checked before deciding some number is a prime)
change fast_prime to
inline void fast_prime(int n)
{
int j;
int rootofn;
rootofn = sqrt(n);
for (int i = 0; ((j = primes[i]) > -1) && (j<rootofn); i++) {
if (!(n % j)) {
return;
}
}
printf("%d\n", n);
}

Resources