-1

Code 1:

int solution(vector<vector<int>>& arr){
    int ans, m = arr.size(), n = arr[0].size(); // it is given that m is atleast 1
    for(int i = 0; i < m; i++){
        for(int j = 0; j < n; j++){
            // do something
            // i and j are only used for iterating over the array
        }
    }
    return ans;
}

Code 2:

int solution(vector<vector<int>>& arr){
    int i, j, ans, m = arr.size(), n = arr[0].size();
    for(i = 0; i < m; i++){
        for(j = 0; j < n; j++){
            // do something
        }
    }
    return ans;
}

I thought code2 uses less memory since code1 declares variable j in the for loop m times (This is not true as mentioned in comments and answer). But I was doubtful when I saw many coders in online coding platforms preferring to use code1 over code2.

I appreciate any explanation about the difference in memory used for the two codes.

susanth29
  • 356
  • 1
  • 2
  • 17
  • 10
    (1) is always better, unless you need the variables outside of the loop. Any sane compiler will compile them to the same thing. – HolyBlackCat Aug 06 '21 at 10:28
  • They are identical. The memory used value is almost certainly just heap memory, and none of those variables affect it in any way. – Retired Ninja Aug 06 '21 at 10:29
  • @susanth29: This is a good starting point: https://en.cppreference.com/w/cpp/language/as_if. In summary, your source code is the *intention*. What the compiler actually produces is down to it. – Bathsheba Aug 06 '21 at 10:53
  • 1
    Just explore the produced assembly yourself by using godbolt.org. It's a great online compiler to explore code snippets with. – Andreas Brunnet Aug 06 '21 at 10:53
  • 3
    There's a lot, a lot more to learn about C++ than these kinds of trivialities. There's a lot more about C++ [to be found in a good textbook](https://stackoverflow.com/questions/388242) than on web sites that have nothing but lists of useless programming puzzles that nobody really cares about. – Sam Varshavchik Aug 06 '21 at 11:02

1 Answers1

1

As Andreas Brunnet suggested I tried compiling both codes in godbolt.org and as HolyBlackCat said the assembly code for both the codes is the same. Here's the code used and the corresponding assembly code (the compiler option is x86-64 gcc 11.2).

Code:

#include <vector>
int sum(std::vector<std::vector<int>> arr) {
    int i, j, ans = 0, m = arr.size(), n = arr[0].size(); // i, j deleted in code2
    for(i = 0; i < m; i++){ // int i = 0 in code2
        for(j = 0; j < n; j++){ // int j = 0 in code2
            ans += arr[i][j];
        }
    }
    return ans;
}

and the assembly code for both the codes is:

sum(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >):
        push    rbp
        mov     rbp, rsp
        sub     rsp, 48
        mov     QWORD PTR [rbp-40], rdi
        mov     DWORD PTR [rbp-12], 0
        mov     rax, QWORD PTR [rbp-40]
        mov     rdi, rax
        call    std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::size() const
        mov     DWORD PTR [rbp-16], eax
        mov     rax, QWORD PTR [rbp-40]
        mov     esi, 0
        mov     rdi, rax
        call    std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::operator[](unsigned long)
        mov     rdi, rax
        call    std::vector<int, std::allocator<int> >::size() const
        mov     DWORD PTR [rbp-20], eax
        mov     DWORD PTR [rbp-4], 0
        jmp     .L2
.L5:
        mov     DWORD PTR [rbp-8], 0
        jmp     .L3
.L4:
        mov     eax, DWORD PTR [rbp-4]
        movsx   rdx, eax
        mov     rax, QWORD PTR [rbp-40]
        mov     rsi, rdx
        mov     rdi, rax
        call    std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::operator[](unsigned long)
        mov     rdx, rax
        mov     eax, DWORD PTR [rbp-8]
        cdqe
        mov     rsi, rax
        mov     rdi, rdx
        call    std::vector<int, std::allocator<int> >::operator[](unsigned long)
        mov     eax, DWORD PTR [rax]
        add     DWORD PTR [rbp-12], eax
        add     DWORD PTR [rbp-8], 1
.L3:
        mov     eax, DWORD PTR [rbp-8]
        cmp     eax, DWORD PTR [rbp-20]
        jl      .L4
        add     DWORD PTR [rbp-4], 1
.L2:
        mov     eax, DWORD PTR [rbp-4]
        cmp     eax, DWORD PTR [rbp-16]
        jl      .L5
        mov     eax, DWORD PTR [rbp-12]
        leave
        ret

and as I understand, lines 18,19,43,45,46,47 in assembly code correspond to line 5 of c++ code and lines 21,22,38,40,41,42 correspond to line 6 (Correct me if I am wrong). i.e.

18:        mov     DWORD PTR [rbp-4], 0
19:        jmp     .L2
43:        add     DWORD PTR [rbp-4], 1
44:.L2:
45:        mov     eax, DWORD PTR [rbp-4]
46:        cmp     eax, DWORD PTR [rbp-16]
47:        jl      .L5

is corresponding code of for((int) i = 0; i < m; i++) and

20:.L5:
21:        mov     DWORD PTR [rbp-8], 0
22:        jmp     .L3
38:        add     DWORD PTR [rbp-8], 1
39:.L3:
40:        mov     eax, DWORD PTR [rbp-8]
41:        cmp     eax, DWORD PTR [rbp-20]
42:        jl      .L4

correspond to for((int) j = 0; j < n; j++)

Clearly, the compiler assigns only one register for j in both codes. So, the memory used is the same.

susanth29
  • 356
  • 1
  • 2
  • 17