-1

So I am making next homework with input numbers to be dissolved to primes multiplication in output. I was confused when it showed up only prime number 2, so I did a proper control dump of the allocated primes array using this function:

long* eratosthen(long max) {
    bool grid[max + 1];

    for(long i = 0; i < max + 1; ++i) {
        grid[i] = true;
    }

    for(long i = 2; i < max + 1; ++i) {
        if(grid[i]) {
            for(long j = i * 2; j < max + 1; ++j) {
                grid[j] = false;
            }
        }
    }

    long *primes;
    primes = (long*)malloc((max + 1) * sizeof(long));

    long index = 0;
    for(long i = 2; i < max + 1; ++i) {
        if(grid[i]) {
            primes[index++] = i;
        }
    }

    return primes;
}

For some unknown reason, the dump says 2 only and ends. Calling for dump is made up by following code:

int main(void) {
    // Prime numbers get calculated first
    long *primes;
    primes = eratosthen(1000000);

    // Control code
    fprintf(stdout, "Control dump of primes array:\n");
    for(long i = 0; i < sizeof(primes) / sizeof(long); ++i) {
        fprintf(stdout, "%li\n", primes[i]);
    }
    int ret = 0;
    /// ...
    return ret;
}

//EDIT: So after all your answers I'll update my question to current state. Main program: int main(void) { // Prime numbers get calculated first long *primes; primes = eratosthen(1000000);

    // Control code
    fprintf(stdout, "Control dump of primes array:\n");
    for( ; *primes != 0 ; primes++) {
        fprintf(stdout, "%li\n", *primes);
    }
    int ret = 0;
}

Generation of primes function:

long* eratosthen(long max) {
    bool *grid;
    grid = (bool*)malloc((max + 1) * sizeof(bool));

    index = 0;
    for(long i = 0; i < max + 1; ++i) {
        *(grid + index) = true;
        index++;
    }

    index = 2;
    index_2 = 2;
    for(long i = 2; i < max + 1; ++i) {
        if(*(grid + index)) {
            for(long j = i * 2; j < max + 1; j += i) {
                *(grid + 2 * index_2) = false;
                index_2++;
            }
            index++;
        }
    }

    long *primes;
    primes = (long *)malloc((max + 1) * sizeof(long));

    index = 0;
    for(long i = 0; i < max + 1; ++i) {
        *(primes + index) = 0;
        index++;
    }

    index = 0;
    index_2 = 2;
    for(long i = 2; i < max + 1; ++i) {
        if(*(grid + index_2)) {
            *(primes + index) = i;
            index++;
            index_2++;
        }
    }

    // free the grid
    free(grid);

    return primes;
}

Like said before, the Ubuntu terminal displays following line:

Neoprávněný přístup do paměti (SIGSEGV) (core dumped [obraz paměti uložen])

translated like this:

Forbidden access to memory (SIGSEGV) (core dumped [memory image saved])

What does it mean and how to get rid of that? :(

Polda18
  • 162
  • 14
  • 4
    1) `++j` --> `j += i` 2) `sizeof(primes)` is size of `long *`. – BLUEPIXY Nov 06 '16 at 05:52
  • Still the same dump :( Thank you, anyway. – Polda18 Nov 06 '16 at 05:59
  • 3
    You try to create an array of `1000000` elements in the stack. The stack is a limited resource, on Windows the default stack-size is only a single MB which you almost use up with your array `grid` in the `eratosthen` function. – Some programmer dude Nov 06 '16 at 06:02
  • [DEMO](http://ideone.com/ISTa1t) – BLUEPIXY Nov 06 '16 at 06:06
  • Interesting. This is a reversed version (returned array instead of passed) of this: [C sizeof a passed array - Stack Overflow](http://stackoverflow.com/questions/5493281/c-sizeof-a-passed-array) – MikeCAT Nov 06 '16 at 06:09
  • `for(long j = i * 2; j < max + 1; ++j) {grid[j] = false;}` - Do you really want to mark all of the numbers greater than or equal to `i*2` false here? (Of course you don't.) – BadZen Nov 06 '16 at 06:18
  • Please do not include comments about urgency — they're wholly inappropriate for questions on SO. – Jonathan Leffler Nov 06 '16 at 06:19
  • @BLUEPIXY: The demo is the same code and returns more primes than mine compilation. I am using gcc in Linux Ubuntu, launched in VirtualBox. Maybe this can help to spot the problém. However, even changing the grid to dynamic allocation, it still returns the only one first prime number and nothing more :( I am freeing the grid in heap after the main function code runs, of course. – Polda18 Nov 06 '16 at 06:20
  • @BadZen: So how do you markup all muptiplies of previous primes to block the sieve? `j =+ i` should do the work, that's I already implemented. @JonathanLeffler: It is urgent since I have to post a working code in time without points penalisation, which is done automatically in each started day with decreasing by one point to negative numbers... – Polda18 Nov 06 '16 at 06:25
  • 1
    Your main program has no idea how many primes were returned. Your use of `sizeof(primes) / sizeof(long)` is grotesquely wrong. It will give you the answer 1 or 2 on most systems, depending on the relative sizes of `long` and `long *`. Apparently on your system, it gives the answer `1` — so you only get to print `2` as a prime. Try doing the printing in the function. Then work out how you can return both the pointer to the array of primes and the size of the array (hint: pass a pointer to one of the returned values as an argument to the function; alternatively, use a structure for the info). – Jonathan Leffler Nov 06 '16 at 06:26
  • @JonathanLeffler: No way :( Tried eigther `sizeof(primes) / sizeof(long)`, `sizeof(*primes) / sizeof(long*)` and both combinations of these two. Still the same result :( – Polda18 Nov 06 '16 at 06:36
  • 1
    What do you mean 'no way'? The expression in `main()` (the one dividing two `sizeof` values) is pointless — it is wrong in its entirety — it will never, ever give you the correct answer — C is not Java — etc. Everyone has been telling you this. You simply cannot determine the size of the array allocated in the function by poking at it from the `main()` function. Your function must tell `main()` what the size of the array is. I outlined a number of methods; any of them can work. But what you're trying will *not* work. – Jonathan Leffler Nov 06 '16 at 06:42
  • @JonathanLeffler So then I can't see these methods in your outline. The function does not have second return value and I can't add this information to the allocated memory for the array. When accessing by a pointer with value addition, it says `Neoprávněný přístup do paměti (SIGSEGV) (core dumped [obraz paměti uložen])` (translated: `Forbidden access to memory (SIGSEGV) (core dumped [memory image saved])`). What does it mean? – Polda18 Nov 06 '16 at 06:57
  • I said: _(hint: pass a pointer to one of the returned values as an argument to the function; alternatively, use a structure for the info)._ You have to change the interface to the function for it to work; or, I suppose, you could use a sentinel value to indicate the end of the useful values in the array (which doesn't require a change of the function prototype — but it still requires modification of the code in `main()` and in the function, of course). The sentinel might be a zero. You must give up on using `sizeof` in `main`. – Jonathan Leffler Nov 06 '16 at 07:03
  • Possible duplicate of [Using sizeof with a dynamically allocated array](http://stackoverflow.com/questions/2731500/using-sizeof-with-a-dynamically-allocated-array) – n. m. could be an AI Nov 06 '16 at 07:13
  • Currently I am filling the prime numbers array with initial zeros and changing the numbers with the heap of zeros after last prime number being unchanged. Then I test the current array item to be zero. If it is not, it takes the value, if it is, it breaks the loop. I am accessing the array by increasing address in the pointer, but it has some weird behaviour. It says `Forbidden access to memory (SIGSEGV) (core dumped [memory image saved])` in the terminal dump... – Polda18 Nov 06 '16 at 07:29
  • @n.m. I didn't find the answer in the link you gave me :( There is an answer marked as solution, but it solves nothing in my case :( – Polda18 Nov 06 '16 at 07:37
  • The answer shows you the error of your ways (i.e. "why do I have an error?" --- here's why). You are supposed to find a solution yourself. – n. m. could be an AI Nov 06 '16 at 07:51
  • "Currently I am filling the prime numbers array with initial zeros and changing the numbers with the heap of zeros after last prime number being unchanged." If you have another question, submit another question. – n. m. could be an AI Nov 06 '16 at 07:52
  • @n.m. I do not have another question, I still want to solve this one particular that still doesn't get solved :( I updated the question to current state, however, which may help to find an answer... – Polda18 Nov 06 '16 at 08:09
  • You have changed the code but no one can see your new code now. Ask a question with your up-to-date code. – n. m. could be an AI Nov 06 '16 at 08:12

1 Answers1

3

The simplest fix to your code is probably to add a sentinel value of 0 to the end of the array of primes, and to rewrite the check condition in main(). As explained extensively in the comments, your current test:

for(long i = 0; i < sizeof(primes) / sizeof(long); ++i) {

is irremediably wrong. You must not attempt to use sizeof because it simply doesn't do what you want it to do.

This code works:

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

static
long *eratosthen(long max)
{
    bool grid[max + 1];

    for (long i = 0; i < max + 1; ++i)
        grid[i] = true;

    for (long i = 2; i < max + 1; ++i)
    {
        if (grid[i])
        {
            for (long j = i * 2; j < max + 1; j += i)   // Key fix
                grid[j] = false;
        }
    }

    long *primes;
    primes = (long *)malloc((max + 1) * sizeof(long));

    long index = 0;
    for (long i = 2; i < max + 1; ++i)
    {
        if (grid[i])
            primes[index++] = i;
    }
    primes[index] = 0; // Sentinel

    return primes;
}

int main(void)
{
    // Prime numbers get calculated first
    long *primes = eratosthen(1000000);

    fprintf(stdout, "Control dump of primes array:\n");
    for (long i = 0; primes[i] != 0; ++i)
    {
        printf("%7li", primes[i]);
        if (i % 10 == 9)
            putchar('\n');
    }
    putchar('\n');
    return 0;
}

I revised the code to print 10 numbers per line. I changed the condition in the loop in main(). And I made two key changes in the function — one to calculate multiples of primes correctly, and the other to add the sentinel at the end of the list of primes.

It produces a list of 78,498 primes starting with

      2      3      5      7     11     13     17     19     23     29
     31     37     41     43     47     53     59     61     67     71
     73     79     83     89     97    101    103    107    109    113

and ending with:

 999563 999599 999611 999613 999623 999631 999653 999667 999671 999683
 999721 999727 999749 999763 999769 999773 999809 999853 999863 999883
 999907 999917 999931 999953 999959 999961 999979 999983

You might note that the code does not release primes — it arguably should. You might note that the space allocated for the primes greatly exceeds the space needed (one million vs less than eighty thousand); you could use realloc() to shrink the space allocated, or use a less conservative (or do I mean less profligate?) estimate on the number of entries needed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278