1

For practice, I want to define a Matrix addition of two 2-D Matrces by pulling the pointers of them. Here is the initiation

const double A[2][2]={{1,2},{3,4}};
double B[2][2]={{4,3},{2,1}};

const double* a=*A;
double* b=*B;

However, since the pointer merely points to the first element of the first array within each matrix, a=*(A+0), how can i go through every element of each Matrix? And I only wnat to use pointer as parameter here.

void D2Add(const double*, double*){
...for loop here...
}
Chrsi
  • 93
  • 5

3 Answers3

2

I only wnat to use pointer as parameter here

That way you will have undefined behavior. The different sub arrays may be placed in different pages/segments in memory and Accessing an array out of bounds is not guaranteed to work. I removed the sentence trying to explain a possible pitfall when accessing a sub array out of bounds because I can't find a good description of it right now.

One way to avoid undefined behavior is to take the arrays by reference instead:

#include <cstddef>
#include <iostream>

template<std::size_t Y, std::size_t X>
void D2Add(const double(&A)[Y][X], double(&B)[Y][X]) {
    for(std::size_t y = 0; y < Y; ++y) {
        for(std::size_t x = 0; x < X; ++x) {
            B[y][x] += A[y][x];
        }
    }
}

int main() {
    const double A[2][2]={{1,2},{3,4}};
    double B[2][2]={{4,3},{2,1}};

    D2Add(A, B);

    for(auto& inner : B) {
        for(auto value : inner) std::cout << value << ' ';
        std::cout << '\n';
    }
}

Output:

5 5
5 5
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • *"may be placed in different pages in memory"* Can you elaborate? AFAIK this is UB only because the standard says so. – HolyBlackCat Aug 24 '21 at 14:46
  • 1
    @HolyBlackCat I'll see if I can find it. – Ted Lyngmo Aug 24 '21 at 14:47
  • 1
    If you meant adjancent pages, then it should work just like a 1D array would work. If you mean non-adjacent pages, then the standard forbids that by requiring arrays to be contiguous. – HolyBlackCat Aug 24 '21 at 14:51
  • @HolyBlackCat "_the standard forbids that by requiring arrays to be contiguous_" - Yes, that sounds familiar too :-) I'm not sure that it should work like a 1D array even if the pages are adjacent though. Not if the compiler is required to produce code that brings the correct page in on the particular platform. I'm very unsure about this part. I'm continuing to look for the SO post I read a long time ago. – Ted Lyngmo Aug 24 '21 at 14:55
  • 1
    @HolyBlackCat I can't find it :-( Perhaps it was only in some comments which makes searching for it a pain. It was probably Lundin or Peter Cordes that wrote something that got me on this track - but I had no luck finding it. I've scratched that part of my answer for now. – Ted Lyngmo Aug 24 '21 at 15:55
  • @HolyBlackCat I'm not sure it's a 100% fit but I found [this answer and comments](https://stackoverflow.com/a/58332627/7582247) that talks about segments in a non-flat memory model, although in a slightly different context. (`<` in C and `std::less` in C++). – Ted Lyngmo Aug 25 '21 at 19:06
  • I'm not sure how that applies. Let's say `void f(int *)` accesses 4 ints through the pointer, and you give it `int[4]`, and then `int[2][2]`. The layout of the two is **guaranteed to be exactly the same**. Other than the optimizer getting confused because of the UB, how can accessing one work, but accessing the other break? – HolyBlackCat Aug 25 '21 at 19:51
  • @HolyBlackCat I'm very unsure .-) Best I found so far - but I'll keep my eyes open for a better explanation of what _could_ happen. – Ted Lyngmo Aug 25 '21 at 19:57
1

This is a very interesting question actually.

Formally, you're indeed only allowed to access the elements of the first sub-array, and trying to access the other one would cause undefined behavior.

But practically, there's a good chance that you might be able to loop from 0 to 4, treating the arrays as 1D arrays of size 4. But I would advise against doing this if possible.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • Cool, thank you. So this method assumes while I create the matrix ( array of arraies), the processor would normally, or tend to, allocate sub-arraries in the same memory as a 1-D array? So if my processor is full-loaded on many tasks, or the allocation does not pass by sequence, it raises error? – Chrsi Aug 25 '21 at 01:38
  • @Chrsi No, it's not up the processor. The sub-arrays will always be next to each other in memory, so this is not a problem. What can happen is the compiler optimizing based on the assumption that you only access the first-subarray, and then the code breaking when the assumption doesn't hold. But such optimizations are unlikely, IMO. – HolyBlackCat Aug 25 '21 at 06:43
1

I Hope you have good understanding of how Multi-Dimensional array is laid in memory.

problem- It is not possible by just pointers until your function has a way to know dimensions of array.

As specified, we need to pass dimensions to functions as well. Since you only want to go through every element, I'll be print each element for demonstration.

void D2Add(const double* ptr, int nRow, int nCol) {
    for (int i=0; i<nRow; i++) {
       for (int j=0; j<nCol; j++) {
           std::cout << *(ptr+(i*nCol)+j) << std::endl;
       }
    }
}
vector X
  • 89
  • 7
  • 2
    This causes undefined behavior, even though it may work in practice. – HolyBlackCat Aug 24 '21 at 14:45
  • `*(ptr+(i*nRow)+j)` will still access the first sub array out of bounds. – Ted Lyngmo Aug 24 '21 at 14:45
  • @HolyBlackCat yeah, If pointer is not pointing any Array. – vector X Aug 24 '21 at 14:49
  • It points to the first sub-array. You're allowed to access that sub-array, but not the other one. – HolyBlackCat Aug 24 '21 at 14:50
  • Are you saying the problem is due to nRow in `*(ptr+(i*nRow)+j)` then, I'm sorry, It was a Typo. I have fixed it. – vector X Aug 24 '21 at 14:55
  • 2
    @vectorX The math wasn't the problem. It's the fact that you're accessing the first sub array out of bounds that makes the program have _undefined behavior_ (but it'll probably work on most platforms). – Ted Lyngmo Aug 24 '21 at 14:58
  • @TedLyngmo I got you. But what I believe that, We can access every Memory location inside our process Address space. Also, there is no way compiler can determine I have passed pointer to first subarray. It is just a memory location. – vector X Aug 24 '21 at 15:07
  • 1
    If there is no way for a compiler to make this distinction, the cost of making this behavior _defined_ in the standard _should_ be minimal (I know, that's kind of a backward argument). Gah... I can't find the post describing the potential _real_ pitfalls by doing this. – Ted Lyngmo Aug 24 '21 at 15:12