Working with a Matrix/2D Array in Your C and C++ programs.

  Рет қаралды 36,922

Jacob Sorber

Jacob Sorber

Күн бұрын

Пікірлер: 84
@fmdj
@fmdj 3 жыл бұрын
Another solution I like and use quite often when I don't know the dimensions of the matrix in advance is to actually just store matrices in one dimension, like int *matrix = new int[rows * cols], then index it with matrix[row * cols + col]. This way the memory is assured to be contiguous and it's easy and efficient to just memcpy the whole array if you need to duplicate it.
@rdcarbonk1885
@rdcarbonk1885 3 жыл бұрын
This is how non sparse matrices are actually handled in general in libraries like eigen c++
@gael6252
@gael6252 3 жыл бұрын
That’s actually really clever
@fmdj
@fmdj Жыл бұрын
@@doradiv10 no you index it by, for instance for the cell where x = row = 1 and y = col = 2: cell = matrix[row*cols+col] = matrix[1*3 + 2] = matrix[5] the index will never be out of bounds as your matrix has size (rows*cols) and the max index is: (rows-1)*cols+(cols-1) = (rows * cols) - 1, which corresponds to the last cell of the (rows*cols) 1D array.
@fmdj
@fmdj Жыл бұрын
@@doradiv10 If I may give you a piece of advice, though you probably know it already: matrix libraries is a solved problem in most environments :) Now I still think any developer should develop a Matrices / Vectors library at least once in their lives as an exercise. It's not very complicated but reasonably enough to be interesting. I very strongly suggest you to code your Matrix library (should you choose to go down that path) using Test Driven Development because if you choose to roll your own lib it will have to be rock solid and TDD is a good and appropriate method to maximize the chances of that happening.
@mrcjproject
@mrcjproject 3 жыл бұрын
Please correct me if am wrong, is there a bug in the for loop from the main scope, specifically accessing memory which is not yours? MATRIX_ROWS same for both loops
@oreo6392
@oreo6392 3 жыл бұрын
One thing to keep in mind is that in C/C++, "const" doesn't actually mean compile time constant and really just means immutable. (C++ does have constexpr for that, but C, at least at the moment, does not) If you use a "const int" as an array specifier for a variable, it will be a VLA, regardless of if the value can be deduced at compile time. This is different from C++ (which doesn't have VLAs). Currently in C the only way to have "MATRIX_ROWS"/"MATRIX_COLS" be a compile time constant is to either use macros or enums. Also, for C23, the committee passed a proposal that makes it such that only stack allocated VLAs with automatic storage duration will be optional with all other types of VMTs/VLAs being mandatory. This means VLAs as function parameters and pointers to VLAs will be mandatory. (this also means "sizeof(int[rows][colls])" will be mandatory)
@wiktorwektor123
@wiktorwektor123 3 жыл бұрын
In "main" and "print_matrix" functions of C program (before refactoring) you have serious bug: you're writing and reading (respectivly) 4 bytes (1 position) behind 2 dimensional array. Second for loop should have condition: col < MATRIX_COLS instead of col < MATRIX_ROWS.
@hatkidchan_
@hatkidchan_ 3 жыл бұрын
That thing was bugging me entire video ngl I was waiting for it to crash, but oh well
@yangliu3754
@yangliu3754 3 жыл бұрын
not seriously a bug. kinda of a typo.
@wiktorwektor123
@wiktorwektor123 3 жыл бұрын
@@hatkidchan_ It may crash or not, but it will change value of next variable in memory you don't wan't for sure.
@wiktorwektor123
@wiktorwektor123 3 жыл бұрын
@@yangliu3754 Reding and writing memory outside of range isn't typo, but serious bug, you can try to investigate for hours, days or weeks.
@yangliu3754
@yangliu3754 3 жыл бұрын
@@wiktorwektor123 as long as you are happy. you are just missing the point. this is not a video about how to write a typo or even bug free program.
@ronnysherer
@ronnysherer 3 жыл бұрын
Good lesson. The next video could be about using one allocation for all ints at once and then just pointing to them. It not only saves many allocations, but it makes sure that the allocated memory is sequential, which might make a performance difference.
@AgnisNeZvers
@AgnisNeZvers 3 жыл бұрын
I prefer doing 1D way - accessing [x + y * columns]. With that allocation is needed only once. It can also work in more dimensions [x + y * columns + z * columns * rows].
@ZeroSleap
@ZeroSleap 3 жыл бұрын
Yeh this flattened multidimensional array approach is nice.Although a bit hard to read,but really nice
@mario7501
@mario7501 2 жыл бұрын
Yeah in C I tend to do this as well. I think that's how most C++ matrix libraries deal with this as well.
@TheRojo387
@TheRojo387 Жыл бұрын
@@mario7501 Now, how did I deduce by myself that that was the technique I needed?
@SriHarshaChilakapati
@SriHarshaChilakapati 3 жыл бұрын
I was taught arrays in slightly different way, and that used to confuse me. An array (the subscript syntax) is a syntactic sugar over pointers. So when one is doing int array[5]; and printing it with printf("%d", array[3]); for example, then they are effectively doing *(array + 3) and printing that value. The name given to an array is always a pointer to the first location, that is, the zeroth cell. So array[x] is the same as *(array + x) and it is pointer math. Having said that, at 16:57, instead of dynamically allocating the memory, you can still create the matrix as int matrix[MATRIX_ROWS][MATRIX_COLS]; and let the compiler actually reserve the memory for you by allocating the values in stack, and when you need to pass to the function, pass a pointer instead. Then you can pass the matrix address to the function where the signature becomes this: void printMatrix(int *matrix, int rows, int cols); And when we need to do matrix[y][x], we access it as *(matrix + x + y * cols). However, one thing that bothered me is I wasn't able to access it as matrix[y][x], even if I pass matrix to the function as a doubly pointer. When tried using IDEOne, it crashed with a Segmentation Fault at runtime. Any idea what might be going on? My program can be found here: ideone.com/GdWlFk (working version). The version that fails: ideone.com/zIg4A7
@edgarbonet1
@edgarbonet1 2 жыл бұрын
Many commenters have suggested flattening the matrix into a 1D array, and indexing it with matrix[row*cols + col], as a flattened matrix is nicer to the cache, and easier to allocate and deallocate. I would like to point out that you can have a flattened matrix and yet keep an array of pointers to rows that lets you have the more convenient syntax matrix[row][col]. This is done as follows: int **matrix = calloc(MATRIX_ROWS, sizeof *matrix); *matrix = calloc(MATRIX_ROWS * MATRIX_COLS, sizeof **matrix); for (int row = 1; row < MATRIX_ROWS; row++) matrix[row] = *matrix + row * MATRIX_COLS;
@michaelclift6849
@michaelclift6849 2 жыл бұрын
And you can also iterate through the entire matrix with a single loop, which is convenient.
@ianmathwiz7
@ianmathwiz7 3 жыл бұрын
3:53 Who else was waiting for him to notice that MATRIX_ROWS in the inner loop should be MATRIX_COLS?
@JacobSorber
@JacobSorber 3 жыл бұрын
I still am. 😀 Sorry about that. It's things like this that make me wish KZbin let me update videos. I understand why they don't, but ...😫
@dankodnevic3222
@dankodnevic3222 4 ай бұрын
@@JacobSorber LOL, maybe to remake it? Funniest thing was when you COPIED loops... I was sure, at that moment, you will see typo...
@LogicEu
@LogicEu 3 жыл бұрын
Hey Jacob, excellent video as always, thank you! Definitely didn't know about those peculiar ways of passing 2D arrays in C functions. You will often encounter another kind of way around this issue, and that is casting everything to a 1D array (as memory is just one string of bytes), and then access it by something like; { array[ row * MATRIX_COLS + col ] = ( row
@zrodger2296
@zrodger2296 3 жыл бұрын
I kind of already knew all this, but only kind of, so this was a great refresher. Like others here I would also like to see how you would do a version where the entire matrix is allocated all at once as an array of int's, and then you manually access them given a row and col. I did this recently in one of my projects.
@tomatus270389
@tomatus270389 3 жыл бұрын
I think you missed the method of allocating the whole matrix as a single continuous array and then using pointer math to get to the element.
@ayecaptainjack6930
@ayecaptainjack6930 3 жыл бұрын
That’s making things a lot more complicate tho
@weirddan455
@weirddan455 3 жыл бұрын
That's probably the way I would do it. You lose a lot of performance with an array of pointers. First, it's a double indirection. Also, it's not very cache friendly. Modern CPUs like things to be stored one right after the other for optimal performance.
@pierreabbat6157
@pierreabbat6157 3 жыл бұрын
That's how I did it in my matrix class, which also handles resizing matrices, adding and multiplying them, Gaussian elimination, and determinants.
@VictorRodriguez-zp2do
@VictorRodriguez-zp2do 3 жыл бұрын
@@ayecaptainjack6930 I had say it's easier and saves you trouble later.
@AIn0n0
@AIn0n0 3 жыл бұрын
@@ayecaptainjack6930 in that case allocation of Matrix is just malloc(sizeof(MX_TYPE) * MAX_X * MAX_Y). Getting n,m element is matrix[n + m * MAX_X] and you still can make it even easier with inlined functions or macros.
@burlapjack8345
@burlapjack8345 3 жыл бұрын
Huh, this video sure was timely. Thanks Jacob.
@yangliu3754
@yangliu3754 3 жыл бұрын
Great as always. Happy that I can follow this time.
@AdisDurakovic
@AdisDurakovic 3 жыл бұрын
Jacob: "I don't wanna confuse anyone" . . . Also Jacob: uses
@JacobSorber
@JacobSorber 3 жыл бұрын
😂. I try.
@nickbrian9882
@nickbrian9882 3 жыл бұрын
I was literally just looking at this topic yesterday!
@afborro
@afborro 3 жыл бұрын
I'll just say, the C++ version is very old school. Prefer std::array over C style array, or use std::vector. this is why some of us love C++, otherwise one may as well just use C if you are going to new and delete everything.
@lean.drocalil
@lean.drocalil 2 жыл бұрын
You know, std::array is essentially just a struct on a template. If you don't need the added features of a true C++ Container, there's no feasible reason to demonize primitive arrays. I'm a big fan of C++, but I hardly ever follow the "the C++ way even if just for the hell of it" advices 😁. Regarding vectors, I've had cases (specifically, writing an emulator in C++) in which going with a C-styled array gave me performance, std::vector was introducing too much overhead, even when previously reserved more memory. Standard C is (mostly) standard and valid C++ and when picking a style between the two, I always go with the simplest and most straightforward (I usually printf over std::cout, too).
@rustycherkas8229
@rustycherkas8229 2 жыл бұрын
@18:30 (switching to alloc'd buffers) The use of "**" probably scares beginners. The alternate equivalent is, of course, int *matrix[] = calloc.... Even though they are the same, the square bracket version provides a clue (especially in the parameter list of the print function) that the var points to a contiguous array... void main( int argc, char *argv[] ) { ......
@SlideRSB
@SlideRSB 2 жыл бұрын
Flat indexing for the win.
@yooyo3d
@yooyo3d 3 жыл бұрын
Did you know... Assume following int a[10]; a[5] = 3; This is the same as *(a+5)=3. This is also the same as *(5+a) =3. So one can write 5[a] = 3 and it should compile and work. Similar pointer math is behind matrices as well. You can show people how compiler internally calculate the address of memory location. Also rows pointers version of matrix is more flexible in a way that each row can have different number of elements, which is not true matrix... It's more like array of arrays.
@nemis123
@nemis123 2 жыл бұрын
Thank you for this video, very informative.
@mohammadImanmansouri
@mohammadImanmansouri Жыл бұрын
Best teacher i love your channel
@JacobSorber
@JacobSorber Жыл бұрын
Thank you.
@LoesserOf2Evils
@LoesserOf2Evils 3 жыл бұрын
Dr. Sorber, what's the difference between a vector and a two-dimensional array? I'd like to see a video on making a class out of this.
@RmFrZQ
@RmFrZQ 3 жыл бұрын
*Double pointers are matrices\2D arrays.* This makes understanding and *working with* double pointers (ex: **argv) much easier, especially because how C threats pointers in a special way.
@italianbeans877
@italianbeans877 3 жыл бұрын
Nah that’s not true. Declaring a pointer vs declaring an array are two different things; char *a = “foo” vs char b[] = “bar” behave unlike each other (a cannot be indexed as it points to space in the text area of its process memory, but b can). The confusion arises between arrays and pointers when passing arguments; an array is passed as an arg via a pointer to its first value.
@bbq1423
@bbq1423 3 жыл бұрын
@@italianbeans877 Both a and b behave the same, you can index a no problem and it will do what you expect. They mean slightly different things though.
@TarousDT
@TarousDT 2 жыл бұрын
I am confused about why you didn't get an access violation/out of bounds error with both nested for loops due to using MATRIX_ROWS with col
@ifstatementifstatement2704
@ifstatementifstatement2704 3 жыл бұрын
#include
@zxuiji
@zxuiji 2 жыл бұрын
defining the size of an argument with other arguments, that's a new trick to me, still, I think I'll stick to **mat rather than mat[rows][cols], it's cleaner, more consistent (binary wise) and still simple to understand
@chonchjohnch
@chonchjohnch 3 жыл бұрын
For my sudoku program, I used triple pointers to make my columns and cells constant time access lol
@AinurEru
@AinurEru 2 жыл бұрын
Alternatively, this works in all compiles for both C and C++ with no need for VLA and no need for allocating arrays on the heap: void print_matrix(int rows, int cols, int matrix[]) { for (int row = 0; row < rows; row++) { printf("%d:\t", row); for (int col = 0; col < cols; col++) printf("%x ", matrix[row*cols + col]); printf(" "); } } int main() { int matrix[MATRIX_ROWS][MATRIX_COLS]; for (int row = 0; row < 3; row++) for (int col = 0; col < 4; col++) matrix[row][col] = (row
@papaulogamerofc946
@papaulogamerofc946 3 жыл бұрын
A question: why did you use "col < MATRIX_ROWS" instead of "col < MATRIX_COLS" in both of your for loops?
@wiktorwektor123
@wiktorwektor123 3 жыл бұрын
It's a bug, second loop should be col
@JacobSorber
@JacobSorber 3 жыл бұрын
Yep, that's called a typo (and a bug). 😫 Thanks for catching it.
@papaulogamerofc946
@papaulogamerofc946 3 жыл бұрын
@@JacobSorber Oh, OK. Good video anyways. :)
@wiktorwektor123
@wiktorwektor123 3 жыл бұрын
@@JacobSorber In this case it's bug, not a typo ;)
@JacobSorber
@JacobSorber 3 жыл бұрын
@@wiktorwektor123 It's both.
@abhi3142
@abhi3142 4 ай бұрын
How would the double pointer method work for static or fixed length array (preserving the array indexing)?
@richardbenes9
@richardbenes9 3 жыл бұрын
Nice video. If I ever decided to use C/CPP for working with matrices, it would be for performance reasons (and, well, I tend to prefer performance in just about any case). This leads me to one, for me interesting, topic - using vectored instructions for number crunching. Would it be possible to touch this in some upcoming video? How to use them, how to determine whether they are available on that specific machine etc...
@rogo7330
@rogo7330 3 жыл бұрын
I prefer 1D arrays with pointers math. It just a more general way to think about data and i don't care how exactly data is structured - just allocate/free/dosmth this much memory and throw it inside function, highlevel code don't care and everything in code looks the same.
@vvinoth514
@vvinoth514 3 жыл бұрын
❤️ from India
@Baptistetriple0
@Baptistetriple0 3 жыл бұрын
why does nobody teach the right way to do 2D arrays in C? this is a naive way that have a lot of cons to it, the better way to do an array of size N * M is to do "int (*arr)[M] = malloc(sizeof(int) * N * M);" here it is the exact same things as if you had declared a static array like "int arr[N][M];", but it is dynamically allocated, you don't need loops to allocate it, and to free it, and you can copy it with just "memcpy(destArr, srcArr, sizeof(int) * N * M);" and the speed benefits of having it contigus in memory.
@oreo6392
@oreo6392 3 жыл бұрын
That's still a VMT. In C11 if you want to define __STDC_NO_VLA__, you also can't support VMTs. Thankfully that was recently changed for C23.
@gaborkiss2206
@gaborkiss2206 3 жыл бұрын
Great video as always! I have a question about using 2D arrays like these on embedded system. The bug in the second for loop could cause some serious problems, since the memory is usually limited. How would you debug it? Is it worth to wrap the 2D arrays in a struct or class and add boundary checks on embedded system, or it adds too much overhead? What's your take on this? I know, it depends on a lot of things, but a general idea or some aspects worth to consider would be very helpful.
@louiearmandtabelisma9816
@louiearmandtabelisma9816 2 жыл бұрын
hi great video is there a way to store output of a counter to a 2d array?
@PavitraGolchha
@PavitraGolchha 3 жыл бұрын
It really irks me how C++ can't handle 2D arrays.
@namphantech
@namphantech 3 жыл бұрын
do you can explained maxtrix[row][col]=(row
@vespert0
@vespert0 3 жыл бұрын
Your videos are really nice. Could you focus more on the linking process? And debugging existing real applications? And cross-compiling? Where does that "unable to find symbol" error come from? What's __dso_handle anyway? Why is the linker complaining about a library if I'm giving it the correct path in -L and --verbose is showing me it's actually finding it but ignoring it? While your videos are great for begginers, it seems as though you're passively contributing to the college falicy that newly-grads will start working in developing new software, when 99% of the time they'll be supporting existing (often legacy) apps. There are *a lot* of linker errors and debugging issues that make sense to clarify. Just a suggestion.
@cmdlp4178
@cmdlp4178 3 жыл бұрын
In my opinion this nested array allocation is bad for teaching, because it makes beginners think, that as much as possible should be allocated on the heap. I think that it is important for beginners to think about the layout of nested C arrays. The important thing is that is missing here is that such nested C arrays are just simple arrays, that are indexed in a certain way. The index is computed by multiplying the number of colums with the row and adding the column to it. Implementing this on a simple 1D array shouldn't be hard. When trying to make it compatible with C++/any C compiler, this is what is usually used in common apis. It is also the most efficient, because no additional memory is used for pointers and the allocation control structures in the allocator used for allocating all the rows. And also it is efficient, because the access does not have an additional indirection, that comes with the additional pointer dereference, which would mean that it is more cache friendly.
@guilhermefe100
@guilhermefe100 9 ай бұрын
for(int... this declaration is already too advance for mee
@catapl93
@catapl93 Жыл бұрын
You're explanations are very chaotic, you don't finish ideas, you keep going back and forth between different ideas and it's just way too much information thrown at once.
@caleb7799
@caleb7799 2 жыл бұрын
yall keep losing me by going off tangents and showing all the other things we will show later, or something about compiler parts or some other thing or maybe this thing... damn.
@windowsxseven
@windowsxseven 2 жыл бұрын
I do not trust this ''Jacob''.
Fixed and Variable Length Arrays in C and C++
20:24
Jacob Sorber
Рет қаралды 45 М.
Lazy days…
00:24
Anwar Jibawi
Рет қаралды 6 МЛН
Smart Sigma Kid #funny #sigma
00:33
CRAZY GREAPA
Рет қаралды 8 МЛН
Creative Justice at the Checkout: Bananas and Eggs Showdown #shorts
00:18
Fabiosa Best Lifehacks
Рет қаралды 8 МЛН
Multidimensional Arrays in C++ (2D arrays)
20:21
The Cherno
Рет қаралды 202 М.
How to make memory read-only in your C programs.
12:57
Jacob Sorber
Рет қаралды 20 М.
you will never ask about pointers again after watching this video
8:03
When do I use a union in C or C++, instead of a struct?
11:18
Jacob Sorber
Рет қаралды 70 М.
31 nooby C++ habits you need to ditch
16:18
mCoding
Рет қаралды 827 М.
What's the Best Way to Copy a Struct in C and C++?
13:44
Jacob Sorber
Рет қаралды 34 М.
Dynamic Arrays in C
11:46
Dylan Falconer
Рет қаралды 70 М.
Creating a 2D Array / Matrix Class in C++ (Part 1)
23:28
Michael Roe
Рет қаралды 15 М.
Another way to check pointers at runtime in C
12:16
Jacob Sorber
Рет қаралды 13 М.
C++ Pointers - Finally Understand Pointers
15:56
Caleb Curry
Рет қаралды 218 М.
Lazy days…
00:24
Anwar Jibawi
Рет қаралды 6 МЛН