Search code examples
cprimes

What is causing this function to return nothing sometimes?


I have this function that is supposed to return an array of prime numbers from 2 to n, but sometimes it doesn't return anything and just says "exited with code=3221225477", specificaly, if I enter a value over 3 or 4. When it does work, it skips over the number 5 and prints "2 3 29541 7 11 ...".

Can someone point out what's wrong with it?

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int *primes_in_range(int stop){
    int *array_primes = malloc(sizeof(int));
    int size = 1;
    int aim;
    int prime;

    array_primes[0] = 2;

    for (int number = 3; number <= stop; number += 2){
        aim = sqrt(number);

        for (int index = 0; index < size; index++){
            prime = array_primes[index];

            if ((number % prime) == 0){
                break;
            }
            else if (prime >= aim){
                array_primes = realloc(array_primes, sizeof(int)*size);
                array_primes[size] = number;
                size += 1;
                break;
            }
        }
    }
    return array_primes;
}

int main(){
    int *result = primes_in_range(8);
    
    for (int i=0; i<8; i++) printf("%d\n", result[i]);
    free(result);

    return 0;
}

I wrote a program following the same algorithm in python and it didn't skip any numbers, so it must be for a different reason that it doesn't work unless I missed something.

I'll leave the working python code here:

def primes_in_range(stop: int = None):
    prms = [2]

    for num in range(3, stop+1, 2):
        aim = num**0.5

        for prm in prms:
            if not num % prm:
                break
            elif prm >= aim:
                prms.append(num)
                break

    if stop >= 2:
        return prms
    else:
        return []


print(primes_in_range(13))

Solution

  • You need to increment the size variable before the call to realloc, then use size - 1 as the index for the new value. As it stands, your program is writing to a value (array_primes[size]) that is outside the range of the allocated buffer and will cause undefined behaviour (which will crash the program … sometimes).

    Further, the 'weird' numbers you are seeing at the end of your list are also values being read from beyond the allocated buffer, because you always assume there will be 8 values (which there won't be). To fix this, add another int* parameter to your function that can return the number of prime number that it found – and use that as the terminator value for your printf loop:

    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    
    int* primes_in_range(int stop, int* found) {
        int* array_primes = malloc(sizeof(int));
        int size = 1;
        int aim;
        int prime;
    
        array_primes[0] = 2;
    
        for (int number = 3; number <= stop; number += 2) {
            aim = sqrt(number);
    
            for (int index = 0; index < size; index++) {
                prime = array_primes[index];
    
                if ((number % prime) == 0) {
                    break;
                }
                else if (prime >= aim) {
                    size += 1; // Increase size BEFORE reallocating!
                    array_primes = realloc(array_primes, sizeof(int) * size);
                    array_primes[size - 1] = number; // The last (new) entry is at index "n - 1"
                    break;
                }
            }
        }
        *found = size; // So we know how many were found
        return array_primes;
    }
    
    int main() {
        int total = 0;
        int* result = primes_in_range(8, &total);
    
        for (int i = 0; i < total; i++) printf("%d\n", result[i]); // Stop at found number
        free(result);
    
        return 0;
    }