C program stops responding for large inputs - c

I am (re-)learning C and in the book I am following we are covering arrays, and the book gives an algorithm for finding the first n primes; myself being a mathematician and a decently skilled programmer in a few languages I decided to use a different algorithm (using the sieve of Eratosthenes) to get the first n primes. Well making the algorithm went well, what I have works, and even for moderately large inputs, i.e. the first 50,000 primes take a bit to run as you would expect, but no issues. However when you get to say 80,000 primes pretty much as soon as it begins a window pops up saying the program is not responding and will need to quit, I made sure to make the variables that take on the primes were unsigned long long int, so I should still be in the acceptable range for their values. I did some cursory browsing online and other people that had issues with large inputs received the recommendation to create the variables outside of main, to make them global variables. I tried this for some of the variables that I could immediately put outside, but that didn't fix the issue. Possibly I need to put my arrays isPrime or primes outside of main as well? But I couldn't really see how to do that since all of my work is in main.
I realize I should have done this with separate functions, but I was just writing it as I went, but if I moved everything into separate functions, my arrays still wouldn't be global, so I wasn't sure how to fix this issue.
I tried making them either static or extern, to try and get them out of the stack memory, but naturally that didn't work since they arrays change size depending on input, and change over time.
the code is:
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
unsigned long long int i,j;
unsigned long long int numPrimes,numPlaces;
int main(void)
{
bool DEBUG=false;
printf("How many primes would you like to generate? ");
scanf("%llu",&numPrimes);
// the nth prime is bounded by n*ln(n)+n*ln(ln(n)), for n >=6
// so we need to check that far out for the nth prime
if (numPrimes>= 6)
numPlaces = (int) numPrimes*log(numPrimes)+
numPrimes*log(log(numPrimes));
else
numPlaces = numPrimes*numPrimes;
if(DEBUG)
printf("numPlaces: %llu\n\n", numPlaces);
// we will need to check each of these for being prime
// add one so that we can just ignore starting at 0
bool isPrime[numPlaces+1];
// only need numPrimes places, since that is all we are looking for
// but numbers can and will get large
unsigned long long int primes[numPrimes];
for (i=2; i<numPlaces+1;i++)
isPrime[i] = true; // everything is prime until it isn't
i=2; // represents current prime
while (i < numPlaces + 1)
{
for (j=i+1;j<numPlaces+1;j++)
{
if (isPrime[j] && j%i ==0) // only need to check if we haven't already
{
isPrime[j] = false;// j is divisibly by i, so not prime
if(DEBUG)
{
printf("j that is not prime: %llu\n",j);
printf("i that eliminated it: %llu\n\n",i);
}//DEBUG if
}//if
}//for
// ruled out everything that was divisible by i, need to choose
// the next i now.
for (j=i+1;j<numPlaces+2;j++)// here j is just a counter
{
if (j == numPlaces +1)// this is to break out of while
{
i = j;
break;
}// if j = numPlaces+1 then we are done
else if (isPrime[j]==true)
{
i = j;
if (DEBUG)
{
printf("next prime: %llu\n\n",i);
}//DEBUG if
break;
}//else if
}// for to decide i
}//while
// now we have which are prime and which are not, now to just get
// the first numPrimes of them.
primes[0]=2;
for (i=1;i<numPrimes;i++)// i is now a counter
{
// need to determine what the ith prime is, i.e. the ith true
// entry in isPrime, 2 is taken care of
// first we determine the starting value for j
// the idea here is we only need to check odd numbers of being
// prime after two, so I don't need to check everything
if (i<3)
j=3;
else if (i % 2 ==0)
j = i+1;
else
j = i;
for (;j<numPlaces+1;j+=2)// only need to consider odd nums
{
// check for primality, but we don't care if we already knew
// it was prime
if (isPrime[j] && j>primes[i-1])
{
primes[i]=j;
break;
}//if, determined the ith prime
}//for to find the ith prime
}//for to fill in primes
// at this point we have all the primes in 'primes' and now we just
// need to print them
printf(" n\t\t prime\n");
printf("___\t\t_______\n");
for(i=0;i<numPrimes;i++)
{
printf("%llu\t\t%llu\n",i+1,primes[i]);
}//for
return 0;
}//main
I suppose I could just avoid the primes array and just use the index of isPrime, if that would help? Any ideas would help thanks!

Your problem is here, in the definition of the VLA ("Variable Length Array", not "Very Large Array")
bool isPrime[numPlaces+1];
The program does not have enough space in the area for local variables for the array isPrime when numPlaces is large.
You have two options:
declare the array with a "big enough" size outside of the main function and ignore the extra space
use another area for storing the array with malloc() and friends
option 1
#include <stdio.h>
unsigned long long int i,j;
bool isPrime[5000000]; /* waste memory */
int main(void)
option 2
int main(void)
{
bool *isPrime;
// ...
printf("How many primes would you like to generate? ");
scanf("%llu",&numPrimes);
// ...
// we will need to check each of these for being prime
// add one so that we can just ignore starting at 0
isPrime = malloc(numPrimes * sizeof *isPrime);
// ... use the pointer exactly as if it was an array
// ... with the same syntax as you already have
free(isPrime);
return 0;
}

The array you allocate is a stack variable (by all likelihood), and stack size is limited, so you are probably overwriting something important as soon as you hit a certain size threshold, causing the program to crash. Try using a dynamic array, allocated with malloc, to store the sieve.

Related

Infinite array index without any pointer in C

I want to get a variable from user and set it for my array size. But in C I cannot use variable for array size. Also I cannot use pointers and * signs for my project because i'm learning C and my teacher said it's forbidden.
Can someone tell me a way to take array size from user?
At last, I want to do this two projects:
1- Take n from user and get int numbers from user then reverse print entries.
2- Take n from user and get float numbers from user and calculate average.
The lone way is using array with variable size.
<3
EDIT (ANSWER THIS):
Let me tell full of story.
First Question of my teacher is:
Get entries (int) from user until user entered '-1', then type entry numbers from last to first. ( Teacher asked me to solve this project with recursive functions and with NO any array )
Second Question is:
Get n entries (float) from user and calculate their average. ( For this I must use arrays and functions or simple codes with NO any pointer )
Modern C has variable size arrays, as follows:
void example(int size)
{
int myArray[size];
//...
}
The size shouldn't be too large because the aray is allocated on the stack. If it is too large, the stack will overflow. Also, this aray only exists in the function (here: funtion example) and you cannot return it to a caller.
I think your task is to come up with a solution that does not use arrays.
For task 2 that is pretty simple. Just accumulate the input and divide by the number of inputs before printing. Like:
#include <stdio.h>
#include <stdlib.h>
int main()
{
float result = 0;
float f;
int n = 0;
printf("How many numbers?\n");
if (scanf("%d", &n) != 1) exit(1);
for (int i=0; i < n; ++i)
{
if (scanf("%f", &f) != 1) exit(1);
result += f;
}
result /= n;
printf("average is %f\n", result);
return 0;
}
The first task is a bit more complicated but can be solved using recursion. Here is an algorithm in pseudo code.
void foo(int n) // where n is the number of inputs remaining
{
if (n == 0) return; // no input remaining so just return
int input = getInput; // get next user input
foo(n - 1); // call recursive
print input; // print the input received above
}
and call it like
foo(5); // To get 5 inputs and print them in reverse order
I'll leave for OP to turn this pseudo code into real code.
You can actually use variable sized arrays. They are allowed when compiling with -std=c99
Otherwise, you can over-allocate the array with an arbitrary size (like an upper bound of your actual size) then use it the actual n provided by the user.
I don't know if this helps you, if not please provide more info and possibly what you have already achieved.

How to add elements from one array into another array of an undefined size based on a condition?

I have been teaching myself C for just a few weeks, and am attempting to write a code that enables the user to decide the size and elements in an array which is then separated into two arrays - one for odd numbers, and one for even numbers.
I am pretty sure that dynamic allocation has something to do with this, but I am unsure of how to implement it. Here is the code so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
//User decides the size of the array of numbers-------------------------------
int n;
printf("How many numbers? ");
scanf("%d",&n);
//User inputs values into array the size of array[n]--------------------------
int i;
int array[n];
printf("What are the numbers?\n");
for(i=0; i<n; i++)
{
scanf("%d",&array[i]);
}
//loop goes through array, separates even and odds into 2 new arrays----------
//use dynamic allocation??
for(i=0;i<n;i++)
{
int *evenarray = malloc(sizeof(evenarray)); //not sure if this is setup correctly
int *oddarray = malloc(sizeof(oddarray)); //not sure if this is setup correctly
if(array[i] % 2 == 0) //if value in array CAN be divided by 2
{
printf("Test statement.\n");
}
else //if this is not true, append to odd array
{
printf("Second test statement.\n");
}
}
}
/*this program accepts a user chosen number of numbers
then, the program separates the odd and even numbers into
two different arrays*/
There is no magical way to get this information at one shot. You can however, try either of the below:
Loop over the first array to figure out the count of odd (or even) numbers, then, you know the count of elements for which memory has to be allocated, and you can use either a VLA (as the first array itself) or use a pointer and allocator functions to allocate memory.
--> However, in this process, you have to perform the odd/even check twice - once to count the occurrence of odd/even numbers and next time, to actually decide and copy them to the new locations.
Allocate two chunks of memory similar to the first array size, and start filling the odd and even elements into the new memory, respectively. After all the elements are stored, take the counts, realloc() the allocated memories to the exact size.
--> In this case, the pre-allocation is to be done, but the odd/even check needs to be carried out only once.
You could copy into the odd/even arrays and keep seperate counters to track it. i.e:
//loop goes through array, separates even and odds into 2 new arrays----------
//use dynamic allocation??
int evencount =0;
int oddcount =0;
int *evenarray = malloc(sizeof(evenarray)); //not sure if this is setup correctly
int *oddarray = malloc(sizeof(oddarray)); //not sure if this is setup correctly
for(i=0;i<n;i++)
{
if(array[i] % 2 == 0) //if value in array CAN be divided by 2
{
printf("Printing to even array.\n");
evenarray[evencount] = array[i];
evencount++;
}
else //if this is not true, append to odd array
{
printf("Printing to odd array.\n");
oddarray[oddcount] = array[i];
oddcount++;
}
}
printf("evenarray = ");
for(i=0;i<evencount;i++){
printf("%d, ", evenarray[i]);
}
printf("\n");
printf("oddarray = ");
for(i=0;i<oddcount;i++){
printf("%d, ", oddarray[i]);
}
printf("\n");

C program to find the n'th prime number-

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int prime(long long int);
long long int *arr; //array to hold n prime numbers
int main()
{
int i,count=4;;
long long int n;
scanf("%lli",&n);
arr=malloc(sizeof(long long int)*n);
arr[0]=2;
arr[1]=3;
arr[2]=5;
arr[3]=7;
if (n==1) printf("%lli",arr[0]);
else{ if (n==2) printf("%lli",arr[1]);
else{ if (n==3) printf("%lli",arr[2]);
else{ if (n==4) printf("%lli",arr[3]);
else
{
for(i=2;count<n;i++)
{
if(prime(6*i-1)) { /*As prime nos are always 6k+1 or
arr[count]=6*i-1; 6k-1fork>=2 I checked only for those*/
count++; }
if(prime(6*i+1)&&count<=n) {
arr[count]=6*i+1;
count++; }
}
printf("%lli",arr[count]);
}}}}
//free(arr);
return 0;
}
int prime(long long int x)
{
int j=1,flag=1;
while(arr[j]<=sqrt(x))
{
if (x%arr[j]==0)
{
flag=0;
break;
}
j++;
}
return flag;
}
The code is working only for n=1,2,3,4, i.e i=0,1,2,3 for which the values are explicitly given. For n=5 onwards it is giving 0 as O/P
There is some glitch related to the global dynamic array as free(arr) is giving core dump error.
Q: Is this the right way to declare a global dynamic array? What could be the problem in this code?
Thank You in advance.
If that is your actual code you have 4 bugs:
2 line comment scopes out a line of your code
the second if should check count < n not count <= n as if count == n you cannot write to arr[count]
You cannot print arr[count] only arr[count-1] which is probably what you mean
In the case where n is less than 4 you still set arr[1], arr[2] and arr[3] which may be out of bounds
It is of course also inefficient to call sqrt(x) in every loop iteration, potentially you should call it outside and there may be a potential rounding issue bug due to the way square roots are calculated, so you might prefer:
while( arr[j] * arr[j] < x )
It would be preferable not to make this global and to pass it into your function.
It would also be preferable to move the main loop logic of your program outside of main().
I'm surprised you say you program works for n=1, 2 and 3 as it looks like you are setting out of bounds.
Your counter goes beyond the size of the array. Specifically both conditions (6i-1 and 6i+1) are met for i=2, and therefore counter is incremented twice, resulting in using arr[5] where you only allocated 5 places in the array. This is because you check counter<=n and not counter
Not sure this could be also be the reason for free creating a core dump, but it is possible (because once corrupting the memory, free may access corrupted data).

Reducing memory usage when designing a sieve of eratosthenes in C

I'm trying to design a sieve of eratosthenes in C but I've run into two strange problems which I can't figure out. Here's my basic program outline. Ask users to set a range to display primes from. If the range minimum is below 9, set the minimum as 9. Fill an array with all odd numbers in the range.
1) I'm trying to reduce memory usage by declaring variable size arrays like so:
if (max<=UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=ULLONG_MAX)
unsigned long long int range[(max-min)/2];
Why doesn't this compile? Variables min and max are declared as ints earlier and limits.h is included. I've commented out the selection structure and just declared unsigned long long int range[(max-min)/2]; for now which compiles and works for now.
2) My code runs but it sometimes marks small primes as non primes.
#include<stdio.h>
#include<limits.h>
void prime(int min, int max)
{
int i, f=0;
//declare variable size array
/*if (max<=(int)UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=(int)ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=(int)ULLONG_MAX)*/
unsigned long long int range[(max-min)/2];
//fill array with all odd numbers
if (min%2==0)
{
for (i=min+1;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
else
{
for (i=min;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
//troubleshoot only: print full range
for (f=0;f<=((max-min)/2);f++)
{
printf("ALL: %d / %d\n", f, range[f]);
}
//display all primes
if (min==9) /*print primes lower than 9 for ranges where min<9*/
printf("2\n3\n5\n7\n");
for (f=0;f<=((max-min)/2);f++) /*print non 0 numbers in array*/
{
if (range[f]!=0)
printf("%d\n", range[f]);
}
}
int main(void)
{
int digits1, digits2;
printf("\n\n\nCalculate Prime Numbers\n");
printf("This program will display all prime numbers in a given range. \nPlease set the range.\n");
printf("Minimum: ");
scanf("%d", &digits1);
if (digits1<9)
digits1=9;
printf("Maximum: ");
scanf("%d", &digits2);
printf("Calculating...");
printf("All prime numbers between %d and %d are:\n", digits1, digits2);
prime(digits1, digits2);
getchar();
getchar();
}
For example, if digits=1 and digits2=200 my program outputs all primes between 1 and 200 except 11 and 13. 11 and 13 are sieved out and I can't figure out why this happens to more and more low numbers as digits2 is increased.
3) Finally, is my sieve a proper sieve of eratosthenes? It kind of works but I feel like there is a more efficient way of sieving out non primes but I can't figure out how to implement it. One of my goals for this program is to be as efficient as possible. Again, what I have right now is:
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
Thanks for reading all of that! I'm sorry for posting yet another sieve of eratosthenes related question and thank you in advance for the help!
No, it is not a proper sieve of Eratosthenes. No testing of remainders is involved in the sieve of Eratosthenes algorithm, Wikipedia is real clear on this I think. :) The whole point to it is to avoid the trial divisions, to get the primes for free, without testing.
How? By generating their multiples, from every prime that we identify, in ascending order one after another.
The multiples of a prime p are: 2p, 2p + p, 2p + p + p, ...
The odd multiples of a prime p are: 3p, 3p + 2p, 3p + 2p + 2p, ...
As we enumerate them, we mark them in the sieve array. Some will be marked twice or more, e.g. 15 will be marked for 3 and for 5 (because 3 * 5 == 5 * 3). Thus, we can start enumerating and marking from p2:
for( i=3; i*i < n; i += 2 )
if( !sieve[i] ) // if `i` is not marked as composite
for( j = i*i; j < n; j += 2*i )
{
sieve[j] = 1; // 1 for composite, initially all are 0s
}
The key to the sieve is this: we don't store the numbers in the array. It is not an array of INTs; it is an array of 1-bit flags, 0 or 1 in value. The index of an entry in the sieve array signifies the number for which the sieve holds its status: marked, i.e. composite, or not yet marked, i.e. potentially prime.
So in the end, all the non-marked entries signify the primes. You will need to devise an addressing scheme of course, e.g. an entry at index i might correspond to the number a + 2*i where a is the odd start of the range. Since your range starts at some offset, this scheme is known as offset sieve of Eratosthenes. A skeleton C implementation is here.
To minimize the memory use, we need to treat our array as a bit array. In C++ e.g. it is easy: we declare it as vector<bool> and it is automatically bit-packed for us. In C we'll have to do some bit packing and unpacking ourselves.
A word of advice: don't go skimpy on interim variables. Name every meaningful entity in your program. There shouldn't be any (max-min)/2 in your code; but instead define width = max - min and use that name. Leave optimizations in the small to the compiler. :)
To your first question: it's a scope thing. Your code is equivalent to
if (max<=UINT_MAX)
{ unsigned int range[(max-min)/2]; } // note the curly braces!
else if (max<=ULONG_MAX)
{ unsigned long int range[(max-min)/2]; }
else if (max<=ULLONG_MAX)
{ unsigned long long int range[(max-min)/2]; }
so there's three range array declarations here, each in its own scope, inside the corresponding block. Each is created on entry to its enclosing block ({) and is destroyed on exit from it (}). In other words, it doesn't exist for the rest of your prime function anymore. Practically it means that if you declare your variable inside an if block, you can only use it inside that block (between the corresponding braces { and } ).
Q1: you can not declare a symbol (here: range) twice in the same scope. It is not exactly your problem but you are trying to do this: you declare range within the if scope and it is not visible outside.

storing known sequences in c

I'm working on Project Euler #14 in C and have figured out the basic algorithm; however, it runs insufferably slow for large numbers, e.g. 2,000,000 as wanted; I presume because it has to generate the sequence over and over again, even though there should be a way to store known sequences (e.g., once we get to a 16, we know from previous experience that the next numbers are 8, 4, 2, then 1).
I'm not exactly sure how to do this with C's fixed-length array, but there must be a good way (that's amazingly efficient, I'm sure). Thanks in advance.
Here's what I currently have, if it helps.
#include <stdio.h>
#define UPTO 2000000
int collatzlen(int n);
int main(){
int i, l=-1, li=-1, c=0;
for(i=1; i<=UPTO; i++){
if( (c=collatzlen(i)) > l) l=c, li=i;
}
printf("Greatest length:\t\t%7d\nGreatest starting point:\t%7d\n", l, li);
return 1;
}
/* n != 0 */
int collatzlen(int n){
int len = 0;
while(n>1) n = (n%2==0 ? n/2 : 3*n+1), len+=1;
return len;
}
Your original program needs 3.5 seconds on my machine. Is it insufferably slow for you?
My dirty and ugly version needs 0.3 seconds. It uses a global array to store the values already calculated. And use them in future calculations.
int collatzlen2(unsigned long n);
static unsigned long array[2000000 + 1];//to store those already calculated
int main()
{
int i, l=-1, li=-1, c=0;
int x;
for(x = 0; x < 2000000 + 1; x++) {
array[x] = -1;//use -1 to denote not-calculated yet
}
for(i=1; i<=UPTO; i++){
if( (c=collatzlen2(i)) > l) l=c, li=i;
}
printf("Greatest length:\t\t%7d\nGreatest starting point:\t%7d\n", l, li);
return 1;
}
int collatzlen2(unsigned long n){
unsigned long len = 0;
unsigned long m = n;
while(n > 1){
if(n > 2000000 || array[n] == -1){ // outside range or not-calculated yet
n = (n%2 == 0 ? n/2 : 3*n+1);
len+=1;
}
else{ // if already calculated, use the value
len += array[n];
n = 1; // to get out of the while-loop
}
}
array[m] = len;
return len;
}
Given that this is essentially a throw-away program (i.e. once you've run it and got the answer, you're not going to be supporting it for years :), I would suggest having a global variable to hold the lengths of sequences already calculated:
int lengthfrom[UPTO] = {};
If your maximum size is a few million, then we're talking megabytes of memory, which should easily fit in RAM at once.
The above will initialise the array to zeros at startup. In your program - for each iteration, check whether the array contains zero. If it does - you'll have to keep going with the computation. If not - then you know that carrying on would go on for that many more iterations, so just add that to the number you've done so far and you're done. And then store the new result in the array, of course.
Don't be tempted to use a local variable for an array of this size: that will try to allocate it on the stack, which won't be big enough and will likely crash.
Also - remember that with this sequence the values go up as well as down, so you'll need to cope with that in your program (probably by having the array longer than UPTO values, and using an assert() to guard against indices greater than the size of the array).
If I recall correctly, your problem isn't a slow algorithm: the algorithm you have now is fast enough for what PE asks you to do. The problem is overflow: you sometimes end up multiplying your number by 3 so many times that it will eventually exceed the maximum value that can be stored in a signed int. Use unsigned ints, and if that still doesn't work (but I'm pretty sure it does), use 64 bit ints (long long).
This should run very fast, but if you want to do it even faster, the other answers already addressed that.

Resources