-5

Why it is giving runtime error while adding printf statement in the last? And just after the removing the printf statement, no error.

#include <stdio.h>

#define MOD 1000000007
#define MAX 44721

int main() {
    long long int test, i, j, store[1000009], n, m, x, a[1000006];
    scanf("%lld", &test);
    for (i = 0; i < 1000006; i++) {
        store[i] = 1LL;
    }
    a[0] = 1;

    for (j = 1; j < 1000006; j++) {
        for (i = 1; i < MAX; i++) {
            if (i % 2 == 0) {
                store[i] = (store[i - 1] + store[i]) % MOD;
            }
        }
        a[j] = store[MAX - 1];
    }
    printf("%lld", a[1]);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 3
    You know, compiler errors actually **mean** something. Including these would probably solve this instantly. – Marcus Müller Feb 08 '16 at 09:31
  • 5
    Either you're misspelling retrun or I've been spelling it wrong all my life and you've found the biggest undiscovered bug in the history of computer programming. – Neil Feb 08 '16 at 09:32
  • 1
    Please read the "how to ask a question" guide. You've got four questions, of which only one has a non-negative score and isn't closed for being a duplicate. – Marcus Müller Feb 08 '16 at 09:33
  • 2
    You're most likely blowing your stack with those arrays (and the compiler probably eliminated all the code & the arrays without the printf since your code had no side-effects). – Mat Feb 08 '16 at 09:34
  • 1
    Wait, did you just convert your compile time error to a runtime error!?!? what is it, now? Considering your `retrun` typo, this doesn't compile. – Marcus Müller Feb 08 '16 at 09:34
  • 1. its `return 0;` not `retrun 0;`, 2. in your variable definitions, you have 1 too many `;` – Magisch Feb 08 '16 at 09:34
  • What Mat said. You should move the `store` and `a` arrays out of `main`, or declare them as `static`. – user3386109 Feb 08 '16 at 09:36
  • I get a `SIGSEGV` with and without the `printf`. Most likely @Mat is correct (as code elimination additionally depends on the actual compiler and optimization level) – Andreas Fester Feb 08 '16 at 09:36
  • sorry all, for mistyping several time. Now it is correct. – user3264956 Feb 08 '16 at 09:37
  • There has been a large increase in these questions recently - those where it's plain that the OP could not have made any attempt even to compile the posted code, never mind link, test and debug it. It would be appreciated by the skilled and experienced enginers on SO if you did not waste their time with umm.. 'economies with the truth'. – Martin James Feb 08 '16 at 10:14
  • @MartinJames Fully agree. SO is not (or at least should not) be a beginner's classroom with handholding every step of the way. – Sujay Phadke Feb 08 '16 at 21:43
  • Correct, I agree with you Martin and Sujay. I apologize but you have also wasted your time here. Thanks guys – user3264956 Feb 11 '16 at 05:25

3 Answers3

1

First of all you should pick a language as C is different from C++. As your code is C my solution will be in C too.

Running your code under Valgrind cleary shows that you are experiencing a stack overflow. The size of the arrays on the stack are too big.

Valgrind output:

==14228== Invalid write of size 4
==14228==    at 0x100000DC7: main (prova.c:6)
==14228==  Address 0x1038c062c is on thread 1's stack
==14228==  in frame #0, created by main (prova.c:6)

The size of the stack is system-dependent, the default on many system is 8MB, on unix/linux you can see it issuing the commnad ulimit -a. You may want to look at this post for more information about how stack and heap works.

The correct solution is to allocate arrays dynamically:

store = malloc(1000009 * sizeof(long long int));
if (store == NULL) {
  // The memory allocation failed, exit
  return(1);
}

a = malloc(1000006 * sizeof(long long int));
if (a == NULL) {
   return(1);
}

Remember to always check the return value of malloc ;)

Community
  • 1
  • 1
terence hill
  • 3,354
  • 18
  • 31
  • Just to be clear, calling malloc is by no means more of a guarantee that it will work. It simply gives your program a chance to do something about it. – Neil Feb 08 '16 at 10:00
  • @Neil what do you mean? It will only fail if you don't have enough memory. I will add the check, I forgot it. – terence hill Feb 08 '16 at 10:01
  • I mean if you just declare an array of 10 million and 9 entries, the allocation is implicit and the program will fail if it can't obtain it whereas in the case of malloc, you can check if it is NULL and react accordingly. The difference between the two is having control over what happens in that case. – Neil Feb 08 '16 at 10:08
  • @Neil yes, of course. I added the check for completeness. However, ten millions entries are not so much on nowadays PCs that have GBs of memory. – terence hill Feb 08 '16 at 10:15
  • You're not just asking for 10 million entries in memory. You're asking for 10 million entires in continuous space in memory, which is not as straightforward. You can have the memory available and not have 8 Mb of continuous space available. You often see large arrays represented by linked lists containing reasonable byte-sized portions (pun intended) in that case to avoid the possibility of not being able to allocate it all. – Neil Feb 08 '16 at 10:23
  • @Neil I C your point ;) , however, I don't agree, com'on that's not the case! 10 million entries of 8 bytes each are 80MB. You use linked lists mostly when you deals with adding and removing a large number of entries to save space not when you have a single big array, unless it has billions or ten of billions elements. – terence hill Feb 08 '16 at 10:34
  • It's a risk I suppose, one that many programmers are unwilling to take. Just sayin'. ;) – Neil Feb 08 '16 at 10:41
0

There's 2 main problems here.

Your code is probably failing because of retrun 0; (fix: return 0;)

Second, you are allocating 2 really big array in the stacks, and you will, 99% of the times, end up getting stack overflow;

Note: long long int, is the same as long long:

You should consider using:

std::vector<long long> store(10000009);

or

std::unique_ptr<long long[]> store = std::make_unique<long long[]> (10000009);

or

   long long* store = new long long[10000009]

or

   auto* store = new long long[10000009]

or if you are using c... since you have both tags

   long long* store = (long long *)malloc(sizeof(long long) * 10000009);

or if you are using MSVC, you can use the __int64 keyword if what you want is a int of 64 bits [8 bytes])

std::vector<__int64> store(1345134123);

I normally prefer that over long long

And you could do a typedef long long __int64 if you end up using another compiler.

Jts
  • 3,447
  • 1
  • 11
  • 14
  • Or just use `new[]`... why not simply stick to C++ language features? – Marcus Müller Feb 08 '16 at 09:38
  • But when we are removing printf statement, its working fine. Can you please check. And if it compiles fine then there is no such problem like overflow because we are still declaring and defining. – user3264956 Feb 08 '16 at 09:39
  • I don't think giving an answer utilizing C++ is useful for a pure C problem – Sujay Phadke Feb 08 '16 at 09:39
  • 1
    @user3264956 your code compiles but doesn't even reach the scanf statement. segfaults due to the large array sizes. – Sujay Phadke Feb 08 '16 at 09:40
  • I am very sure, there is not stack overflow – user3264956 Feb 08 '16 at 09:42
  • My compiler gives me warning when I try to use 16000 bytes in the stack, and you are using 16000 * 61, and you are saying your compiler doesn't give you a warning, or crash with stack overflow? are you using a compiler written in 1998 or smt? – Jts Feb 08 '16 at 09:45
  • 2
    @user3264956 you may be sure. however the OS disagrees. – Sujay Phadke Feb 08 '16 at 09:46
  • 2
    Just because it doesn't crash in a very, very specific case, doesn't mean it won't crash if compiled with smt else, or ran in a different pc, or (different OS). 99% of the times your program will fail, and that's something you don't want. – Jts Feb 08 '16 at 09:47
  • Not sure I understand why you changed all the `long long int` to `long long`. As you indicated yourself these are equivalent so it's a matter of personal style. Therefore I'm not sure where that conversion comes into an answer here. – Lightness Races in Orbit Feb 08 '16 at 11:13
  • @PreferenceBean My main idea was to give him code that is well written and is easy to maintain. But I didn't change his style, I gave him alternatives. I "assumed" that maybe he didn't know that long long int is equivalent to long long, and long long is equivalent to __int64 in MSVC. That's why I explained them. – Jts Feb 08 '16 at 11:24
0

You allocate 2 large arrays of long long int in automatic storage, that's more than 8MB of stack space. You probably cause a stack overflow. It is possible that the compiler optimizes out most of your code if you remove the printf since none of it has any observable behavior without it.

In C, allocate the arrays with malloc:

#include <stdio.h>
#define MOD 1000000007
#define MAX 44721

int main(void) {
    long long int test, i, j, n, m, x;
    long long int *store = malloc(1000009 * sizeof(*store));
    long long int *a = malloc(1000006 * sizeof(*a));

    scanf("%lld", &test);
    for (i = 0; i < 1000006; i++) {
        store[i] = 1LL;
    }
    a[0] = 1;

    for (j = 1; j < 1000006; j++) {
         for (i = 1; i < MAX; i++) {
             if (i % 2 == 0) {
                 store[i] = (store[i - 1] + store[i]) % MOD;
             }
         }
         a[j] = store[MAX - 1];
    }
    printf("%lld", a[1]);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189