1

I allocate a 2D array of char * and every string length is 12.
50 rows and 2000000 columns.

Lets calculate it: 50*2000000 * (12(length)+8(for pointer)). I use 64 bit.

50*2000000 * 20 =2000000000 bits .. -> 2 GB.

When I check the memory monitor it shows that the process takes 4 GB.
(All that happened after allocation)

This is the code:

int col=2000000,row=50,i=0,j=0;
char *** arr;
arr=(char***)malloc(sizeof(char**)*row);
for(i=0;i<row;i++)
{
arr[i]=(char ** )malloc(sizeof(char*)*col);
    for(j=0;j<col;j++)
     {
         arr[i][j]=(char*)malloc(12);
         strcpy(arr[i][j],"12345678901");
         arr[i][j][11]='\0';
     }
}

May that be from the paging in Linux?

Lundin
  • 195,001
  • 40
  • 254
  • 396
IbrahimAsad
  • 516
  • 1
  • 5
  • 16
  • 1
    What is the "memory mentor" ? – cnicutar Jan 28 '14 at 09:07
  • 5
    [do ***NOT*** cast the return value of `malloc()`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858#605858) –  Jan 28 '14 at 09:07
  • 3
    I sincerely hope that `z` is meant to be `j`, or this is no going to do what you (apparently) want it to. (and it isn't needed anyway; the `strcpy` took care of that for you). – WhozCraig Jan 28 '14 at 09:11
  • 1
    `arr[i][z][11]='\0';` ? – BLUEPIXY Jan 28 '14 at 09:11
  • @cnicutar I used top command – IbrahimAsad Jan 28 '14 at 09:11
  • 6
    Unless you have a rock-solid sub-allocator (and you don't), you're getting considerably more memory with those 100000000 allocations of 12-`char`s each than just 12-`char`s each. And your heap-chain is going to get absolutely slaughtered with chain-allocations managing this thing. – WhozCraig Jan 28 '14 at 09:15
  • 1
    @H2CO3; If you do speak English, at least keep in mind, that other people speak less vowel-rich languages with a wide variety of dialects. And that there may be people to whom the audible difference between mentor and monitor is less than the differences between different realisations of each of them in different dialects of English. If one never has noticed a difference between these words, why should she think they are spelled differently? – mafso Jan 28 '14 at 13:30
  • @mafso my native language (Hungarian) is radically different from English, and it's not very easy for us to learn English either. I'm not being anyone for not finding obvious things that are non-obvious (that would be elitism), my problem is that in technology and programming in particular, precision is essential. and if someone knows that his language skills are not good enough, he should do *something* about it (in this case, looking up the potentially confusing words in a dictionary). –  Jan 28 '14 at 14:05
  • (*I'm not "blaming" anyone, of course, that's a typo.) –  Jan 28 '14 at 14:19

2 Answers2

4

Each call of malloc is taking more memory than you ask. Malloc needs to store somewhere its internal info about allocated place, like size of allocated space, some info about neighbors chunks, etc. Also (very probably) each returned pointer is aligned to 16 bytes. In my estimation each allocation of 12 bytes takes 32 bytes of memory. If you want to save memory allocate all strings in one malloc and split them into sizes per 12 at your own. Try the following:

int col=2000000,row=50,i=0,j=0;
char *** arr;
arr= malloc(sizeof(*arr)*row);
for(i=0;i<row;i++)
{ 
  arr[i]= malloc(sizeof(*arr[i])*col);
  char *colmem = malloc(12 * col);
  for(j=0;j<col;j++)
  {
     arr[i][j] = colmem + j*12;
     strcpy(arr[i][j],"12345678901");
  }
}
Marian
  • 7,402
  • 2
  • 22
  • 34
  • Edit: Sry. it *is* too late. I thought you had allocated the whole thing in one shot. you're right. – WhozCraig Jan 28 '14 at 09:23
  • -1, this is a terrible, superfluous hack, and it doesn't even do what's advertised (" allocate all strings in one malloc and split them into sizes per 12 at your own" is what Lundin's answer below does, but not this code). –  Jan 28 '14 at 14:13
  • 1
    @H2CO3 The question was why the original code took more memory than asked by mallocs. I've correctly answered and suggested an experimental code demonstrating my answer. Why do you down vote correct answer? – Marian Jan 28 '14 at 15:27
  • @Marian advising the use of bad practices is not a justification of an otherwise correct explanation. –  Jan 28 '14 at 15:33
  • 1
    @H2CO3 What bad practice I've advised? I've made a minimal change to the original code demonstrating the difference between allocation of many small pieces against allocation of larger. – Marian Jan 28 '14 at 15:37
  • @Marian See Lundin's answer. –  Jan 28 '14 at 15:43
2

I would re-write the code from scratch. For some reason, around 99% of all C programmers don't know how to correctly allocate true 2D arrays dynamically. I'm not even sure I'm one of the 1% who do, but lets give it a shot:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main()
{
  const int COL_N = 2000000;
  const int ROW_N = 50;

  char (*arr)[ROW_N] = malloc( sizeof(char[COL_N][ROW_N]) );

  if(arr == NULL)
  {
    printf("Out of memory");
    return 0;
  }

  for(int row=0; row<ROW_N; row++)
  {
    strcpy(arr[row], "12345678901");
    puts(arr[row]);
  }

  free(arr);

  return 0;
}

The important parts here are:

  • You should always allocate multi-dimensional arrays in adjacent memory cells or they are not arrays, but rather pointer-based lookup tables. Thus you only need one single malloc call.
  • This should save a bit of memory since you only need one pointer and it is allocated on the stack. No pointers are allocated on the heap.
  • Casting the return value of malloc is pointless (but not dangerous on modern compilers).
  • Ensure that malloc actually worked, particularly when allocating ridiculous amounts of memory.
  • strcpy copies the null termination, you don't need to do it manually.
  • There is no need for nested loops. You want to allocate a 2D array, not a 3D one.
  • Always clean up your own mess with free(), even though the OS might do it for you.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The col and row .. is not const ... and the compiler gave error without Casting the return values . Thanks . – IbrahimAsad Jan 28 '14 at 12:03
  • @IbrahimAsad Doesn't matter if they are const or not. Are you sure you aren't compiling on a C++ compiler? That's a different programming language, which is not 100% compatible with C. – Lundin Jan 28 '14 at 13:53
  • @IbrahimAsad if the col and row aren't const, that's fine too (C has variable length arrays), and **you must NOT cast the return value of `malloc`**, because it is harmful (just read the answer I linked to). These errors are typical symptoms of you trying to compile C code with a C++ compiler, which is bad, because they are different languages. So instead of complaining about a correct answer of which the correctness you do not appreciate (since you do not even understand it), rather go ahead, learn C, compile C code with a C compiler, and be humble and accept good advice. –  Jan 28 '14 at 14:11
  • 1
    @H2CO3 Strictly speaking, casting the result of malloc is merely pointless, it is not harmfull on a C99 compiler, because "implicit int" return type has been removed from the language. Meaning that the code won't compile if you use malloc without including stdlib.h, rather than giving you an "implicit int" return type as it did in C90. If you are using a C90 compiler, then indeed it is dangerous practice. And of course if you are using a C++ compiler, you shouldn't be using malloc in the first place. – Lundin Jan 28 '14 at 14:24
  • I don't believe the code posted above will compile on anything but a C99 or C11 compiler, however. The VLA will not compile in C90 nor in C++. – Lundin Jan 28 '14 at 14:25
  • 1
    @Lundin Yeah, C99-doesn't-let-you-do-it-anyway is right, but because not every compiler in the world supports it, it **is** harmful. One other (and perhaps better) reason for it being harmful is that it **decreases readability,** which is the very last thing you want to do with your code. –  Jan 28 '14 at 14:26
  • @Lundin (as long as one doesn't rely GNU and other extensions, anyway. I've seen too much of that crap. :/) –  Jan 28 '14 at 14:26
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46253/discussion-between-lundin-and-h2co3) – Lundin Jan 28 '14 at 15:43