-3

Alright, so, just for fun, I was working on the sieve of eratosthenes. It was working fine intially so I sought out to improve its runtime complexity. and now, I on't know why, but I'm gettig a segmentation fault. Here's the code:

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

int main(void)
{
    int* check = malloc(1000000000 * sizeof(int));
    long long int i;
    for(i = 0;i < 1000000000;i++)
    {
        check[i] = 0;
    }
    int j = 0;
    for(i = 2;i <= 1000000002;i++)
    {
         if(check[i] == 0)
         {
            printf("%lld\n", i);
            for(j = 1;j < (1000000001/i);j++)
            {
                check[j*i] == 1;
            }
         }
    }
return 0;   
}

Any help as to why it fails would be appreciated.

Nalin Bhardwaj
  • 223
  • 1
  • 6
  • possible duplicate of [Getting a stack overflow exception when declaring a large array](http://stackoverflow.com/questions/571945/getting-a-stack-overflow-exception-when-declaring-a-large-array) – 2501 Oct 12 '14 at 17:34
  • 3
    `int check[1000000000];` might be too large for automatic storage ... – wildplasser Oct 12 '14 at 17:34
  • The answer is in the website? – Kerrek SB Oct 12 '14 at 17:34
  • Okay, @wildplasser that was furiously fast, but I have retried declaring the array as a heap array using malloc and stuff but I'm still getting the same errors. – Nalin Bhardwaj Oct 12 '14 at 17:35
  • Give me a min to revise the code @KerrekSB – Nalin Bhardwaj Oct 12 '14 at 17:36
  • try to learn how a debugger works! First: catch the line which runs into trouble. After that, ask the debugger or your system trace what was going on and WHICH exception was thrown. – Klaus Oct 12 '14 at 17:36
  • @Nib: Do you have 4GB of memory on your system? – Kerrek SB Oct 12 '14 at 17:36
  • You can spare yourself the first for-loop by initializing the array. – Kerrek SB Oct 12 '14 at 17:38
  • Check the return value of `malloc`, it's probably `NULL`. – interjay Oct 12 '14 at 17:38
  • @KerrekSB how can we initialze an entire array ? (without for loop), and yes I have 8gigs of RAm on my machine – Nalin Bhardwaj Oct 12 '14 at 17:41
  • 1
    @Nib Just let me confirm, do you use 64 bit OS and compile your code into a 64 bit executable? Otherwise your 8 GB RAM is of limited use. – nodakai Oct 12 '14 at 17:44
  • Whoa, 2 downvoted ??? Why, they haven't been able to solve my issues... – Nalin Bhardwaj Oct 12 '14 at 17:51
  • @2501 thanks really it worked but IDK what happened, ever since I executed the program, I didn't get a SIGSEGV but now my computer's jammed. It's stuck :( – Nalin Bhardwaj Oct 12 '14 at 17:53
  • 1
    If your compiler isn't warning you about `check[j*i] == 1;` being a statement without side-effects in some shape or form, you either need to turn on more warnings or you need to get a better compiler. Comparing for equality isn't ever going to change the array, so you're going to get a lot of spurious primes reported. – Jonathan Leffler Oct 12 '14 at 17:55
  • @JonathanLeffler its not and I use gcc – Nalin Bhardwaj Oct 12 '14 at 17:56
  • 1
    If you use GCC, use `-Wall -Wextra -Werror` at minimum. I add `-Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wold-style-declaration` for good measure, and sometimes `-Wshadow` and sometimes a few others. Starting with the 'mighty trio' would be a good place to get going. – Jonathan Leffler Oct 12 '14 at 17:56
  • 1
    @Nib: `calloc` allocates and zero-initializes an array. – Kerrek SB Oct 12 '14 at 18:02

2 Answers2

0

Your code has multiple errors, any of which could explain a segfault. First, you have not checked the return value of malloc, which may be NULL, even when you are totally sure it couldn't be.

Second, you are exceeding the bounds of the array you've allocated when you iterate i from 2 to 1000000002. With so many zeros it's hard to eyeball, so here are your figures with separators:

Initial allocation: 1,000,000,000
Range of i: 2 to 1,000,000,002 inclusive

At the end of that loop you are accessing memory past the end of your array.

Eric Melski
  • 16,432
  • 3
  • 38
  • 52
0
#include <stdio.h>
#include <stdlib.h>

#if 1
static const size_t N = 1000 * 1000 * 1000;
#else
static const size_t N = 1000;
#endif

Don't use a magic number, define it as a constant. 1000000000 is also hard to read. Your C compiler can do calculation for you before it emits an executable. And you should have started with a small number. If you change #if 1 into #if 0, then the #else clause defining N as 1,000 will take effect.

int main(void)
{
    char* check = malloc(N + 3);

When you essentially use check as a boolean array, it doesn't have to be of type int. int occupies 4 bytes whereas char only 1 byte.

    if (NULL == check) {
        perror("malloc");
        abort();
    }

malloc silently returns NULL when it failed to find a memory chunk of the specified length. But if you work with 64 bit OS and compiler, I don't think it's likely to fail...

    long long int i;
    memset(check, 0, sizeof(check[0]) * (N + 3));

memset fills an array with the value of the 2nd parameter (here 0.) The third parameter takes the number of BYTES of the input array, so I used sizeof(check[0]) (this is not necessary for a char array becuase sizeof(char)==1 but I always stick to this practice.)

    int j = 0;
    for(i = 2;i <= N+2;i++)
    {
         if(check[i] == 0)
         {
            printf("%lld\n", i);
            for(j = 1;j < ((N+1)/i);j++)
            {
                check[j*i] = 1;

You wrote check[j*i] == 1 but it was an equality test whose result didn't have any effects.

            }
         }
    }
    free(check);

It is a good practice to always free the memory chunk that you allocated with malloc, regardless whether free is necessary or not (in this case no, because your program just exits at the end of sieve calculation.) Perhaps until you become really fluent with C.

return 0;   
}
nodakai
  • 7,773
  • 3
  • 30
  • 60
  • @Nib I ran the revised code with `N` = 1,000 at this online compiler website http://ideone.com/taIfr4 Your code has a minor bug at the end of sieve, but in general work as expected for `N` = 1,000. – nodakai Oct 12 '14 at 18:19
  • 1
    Using a massive array of 4-byte `int`s to hold 0 or 1 uses a lot of unnecessary memory. Without bit-twiddling, you can use an array of `char` instead of `int` to use just a quarter of the space. With bit twiddling, you could get 8 values stored per byte of allocated space (so that's 1/32 of the original space). If you further observe that every even number other than 2 is non-prime, you can save a further factor of two by only recording the status of odd numbers, for an overall space saving factor of 64. The bit twiddling code is probably too fiddly to be appropriate for the OP as yet. – Jonathan Leffler Oct 12 '14 at 21:01