0

I have this piece of code from my teacher:

photo

and I'm trying to understand how does he create this 2D array.

with the line

a=(float**)calloc(m,sizeof(float*)); 

I think that he allocates spaces for the lines.

The lines that I don't really understand is

a[0]=(float*)malloc(m*n,sizeof(float));

and the for loop.

Wouldn't a[0] contain an array of size m*n? What's the point in that? Shouldn't a[0] contain an array of size n, which would represent the column, then a[one] (if I write 1 instead of one it will create a link to the same photo again) another array of size n, and so on?

letsintegreat
  • 3,328
  • 4
  • 18
  • 39
  • This isn't a 2D array. `malloc` only takes 1 parameter. And lots of other problems. Whoever wrote this was confused and shouldn't be teaching C. See [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Lundin Jan 29 '21 at 14:43
  • I believe your instructor is trying to use the second technique described in [question 6.16](http://c-faq.com/aryptr/dynmuldimary.html) of the old [C FAQ list](http://c-faq.com/). The pictures there should help you understand this. – Steve Summit Jan 29 '21 at 14:49
  • 1
    I guess the `malloc` should have been `calloc`. – Ian Abbott Jan 29 '21 at 14:50
  • The correct code is `#include `... `float (*a)[n] = calloc(m*n, sizeof(float));` then access with `a[i][j] = something;` then `free(a);` on a single line. Everything else is teacher incompetence. – Lundin Jan 29 '21 at 14:58
  • 1
    @Lundin Well yes, but VLA support is optional. – Ian Abbott Jan 29 '21 at 15:00
  • @Lundin would you mind writing a in-detail answer about this, as you seem to know what's going on? :) Let's say it was only a typo, and instead of m,sizeof(float*) he meant to write m*sizeof(float*). Is there anything wrong with the code besides that? –  Jan 29 '21 at 15:05
  • @IanAbbott Only use useful compilers. If you somehow manage to find a post C99 compiler without VLA support then don't use it. Doesn't really matter though, even without VLA you'd use old school C89 "mangled arrays". The point here is that anything that doesn't give a single malloc/calloc call is wrong. – Lundin Jan 29 '21 at 15:05
  • @OctavianNiculescu The link I gave you in the first comment already explains this in great detail. – Lundin Jan 29 '21 at 15:05
  • @Lundin I'll look into it. Thanks –  Jan 29 '21 at 15:07
  • 1
    @OctavianNiculescu You should know that it is Lundin's opinion when he says that "Everything else is incompetence". The array-of-pointers technique your teacher was (trying to) use is perfectly valid. – Steve Summit Jan 29 '21 at 15:09
  • @SteveSummit I see. Then would you mind answering my questions, please? –  Jan 29 '21 at 15:11
  • @SteveSummit Valid until benchmarking. It's not opinion but a fact that two malloc calls will cause 1) far slower allocation and 2) far slower data look-up due to cache misses. Then on top of that there's heap fragmentation. All of this for absolutely nothing gained but obfuscated code with multiple loops. – Lundin Jan 29 '21 at 15:11
  • @Lundin There are sometimes good reasons to avoid variable length variables, but perhaps no good reason to not support variable length types. – Ian Abbott Jan 29 '21 at 15:12
  • @OctavianNiculescu I already answered! (25 years ago, in fact. :-) ) See my comment "I believe your instructor is trying to use..." above. – Steve Summit Jan 29 '21 at 15:12
  • @SteveSummit I saw it after I had posted :) thanks. –  Jan 29 '21 at 15:14
  • @Lundin well yes. My teacher's approach is a valid one (it does create a 2d array) but I think that it makes no sense to use it when you've got a better approach on the link that you'd given me. Thanks :) –  Jan 29 '21 at 15:15
  • @OctavianNiculescu No it creates an array of pointers which sits in one segment of the heap taking up space and lagging your program down. And then it creates another array which is a 2D array of floats, which sits in another segment of heap space. – Lundin Jan 29 '21 at 15:19
  • How can I see that myself? I'm not saying you're wrong, I just want to see how this happens behind the scenes. Can I use a debugger for that? –  Jan 29 '21 at 15:22
  • @OctavianNiculescu Just `printf("%p")` the address pointed at by `a` vs the address pointed at by `a[0]`. A debugger would also show you completely different addresses for the two. – Lundin Jan 29 '21 at 15:24
  • Yes, you're right. I see your point now. –  Jan 29 '21 at 15:27

1 Answers1

-1

The purpose of this line

a[0]=(float*)malloc(m*n*sizeof(float));

is to allocate a block of data large enough for the entire matrix.

The first line points straight into this block, and the loop

for (int i = 1; i < m; ++i)
    a[i] = a[i-1] + n;

sets up the pointers for each line to point into the appropriate section of this block of data.

Sven Nilsson
  • 1,861
  • 10
  • 11
  • The `malloc` call here from the original text has the wrong number of parameters though. – Ian Abbott Jan 29 '21 at 14:53
  • The purpose of the line is to generate the compiler error "too many arguments to function malloc". – Lundin Jan 29 '21 at 14:54
  • The point here is rather that this slop should never have been handed out to students in the first place. – Lundin Jan 29 '21 at 14:55
  • You are right in the sense that it is a bit of a hack, not suitable for beginners at all. – Sven Nilsson Jan 29 '21 at 14:56
  • It's not suitable for anyone. Why would you have a segmented pointer-lookup when you could have a faster and less memory consuming 2D array with simpler syntax? – Lundin Jan 29 '21 at 14:59
  • The hack is potentially faster, only two memory allocation calls. Perhaps also better data localization, speeding it up even more due to less cache misses... – Sven Nilsson Jan 29 '21 at 15:05
  • The point is: why two malloc calls when you only need one? – Lundin Jan 29 '21 at 15:06
  • I accepted your answer because it was the response to my question - even though it might not be the right decision to use this approach (according to Lundin, I've not looked into it yet). –  Jan 29 '21 at 15:13
  • Thanks. If you want a "real" 2d array, you need something similar to your teachers example. But you can instead use an 1d array and access the elements with pointer arithmetic, i.e. arr[y * n + x] instead of arr[y][x] . This is the very fastest method, and will save memory. – Sven Nilsson Jan 29 '21 at 15:35