0

I'm trying to create a 3 Dimensional array S[ ][ ][ ]...

when the size is small for example:

  m=40;  
  int S[m][m][m];
  memset(S, 0, sizeof(S[1][1][1])*m * m * m);  //initialize all the array with 0//
  for (i=1 ; i<=m ; i++ )  { 
      k=1;
     for (j=1 ; j<=n ; j++ ) {
       if(statement) {   //if statment true i put in S array a value//
       S[i][i][k]=j;    k++;}

it works fine(for small size like S[ 40 ][ 40 ][ 40 ]... When the size is big, for example:

  m=1500;
  int S[m][m][m];
  memset(S, 0, sizeof(S[1][1][1])*m * m * m);
  ....
  ....

My program stop working probably for memory usage or something like, that i don't know for sure...Any idea?

Thanks.

Nakos Kotsanis
  • 180
  • 1
  • 15
  • `m=1500; int S[m][m][m];` is too big for the stack. Use `malloc`. – BLUEPIXY Oct 01 '17 at 00:34
  • I know... But i have to read a 2 files with 15.000 chars (m) and 20.000 chars(n). Then i have to put in my 3-dimensional array S some value like example: S[1][1][1]=4, S[1][1][2]=8,...S[1][1][m]=500, S[2][2][1].....until S[m][m][m]=x... any idea to make this one work? – Nakos Kotsanis Oct 01 '17 at 00:37
  • 1
    Also `i=1 ; i<=m` --> `i=0 ; i – BLUEPIXY Oct 01 '17 at 00:40
  • 2
    `int (*S)[m][m] = malloc(m * sizeof *S);` – mch Oct 01 '17 at 00:43
  • i start for 1 and not from 0 because i have to leave an empty space for my code... for example array A[m] --> A[0]=null, A[1]=x,A[2]=y.....A[m]=z.... – Nakos Kotsanis Oct 01 '17 at 00:43
  • There is no problem starting from 1, but `m` can not be used as index. (It's out-of-bounds error) – BLUEPIXY Oct 01 '17 at 00:44
  • 1
    You are also indexing past the bounds of the array. Array indices in C are zero-based, so in your case 0 through m-1. You need to fix that before doing anything else. – Tom Karzes Oct 01 '17 at 00:47
  • Tom i have to leave an empty space in array A[0] ,S[0][0][0] but still if i change it to start the for from 0 and not from 1 the problem remains with the memory of S(1500^3)... – Nakos Kotsanis Oct 01 '17 at 00:58
  • 2
    `memset(S, 0, sizeof(S[1][1][1])*m * m * m);` -> `memset(S, 0, sizeof S);` – David C. Rankin Oct 01 '17 at 00:58
  • Thanks David, that seems better use of memset but still the problem with S remains... – Nakos Kotsanis Oct 01 '17 at 01:02
  • `A[0]=null, A[1]=x,A[2]=y` does not make sense. What is `null` supposed to be? THe ideomatic way is to start indexing an array from `0` in C. Anything else will confuse the reader and degrade maintainablity. If you have to store additional data about the array, use a `struct`. – too honest for this site Oct 01 '17 at 01:17
  • Note that the array using size 40 only needs about 256 KB; the array using size 1500 needs about 13.5 GB. You need a fairly substantial machine to create that size of array, even with virtual memory. – Jonathan Leffler Oct 01 '17 at 04:43
  • What should code do if there is not enough memory? – chux - Reinstate Monica Oct 01 '17 at 12:03

2 Answers2

2

You’ll have to allocate such a large array dynamically. Here’s one method:

m = 1500;
int (*S)[m][m] = calloc( m, sizeof *S );
if ( !S )
{
  fprintf( stderr, “Fatal: unable to allocate array\n” );
  exit( EXIT_FAILURE );
}

for ( i = 0; i < m; i++ )
{
  k = 0;
  for ( j = 0; j < m; j++ )
  {
    if ( expr )
    {
      S[i][i][k++] = j;
    }
  }
}

free( S );

Edit

Thinking about it, it takes on the order of 12.5 Gb to store 15003 4-byte integers; you won't be able to do that on a 32-bit system (which can only support up to 4 Gb virtual address space). You'd need a 64-bit system, but even then it's possible you won't be able to allocate that much space in a single, contiguous block.

An alternative is to do a piecemeal allocation, like so:

bool success = true; 
size_t i, j;
m = 1500;
int ***S = calloc( m, sizeof *S );
if ( !S )
  // bail out here

// Breadth-first allocation strategy, we allocate all a[i] first,
// make sure they all succeeded, and *then* allocate each a[i][j].
for ( i = 0; success && i < m; i++ )
{
  S[i] = calloc( m, sizeof *S[i] );
  success = (S[i] != NULL );
}

// If allocating any S[i] failed, free all S[0] through S[i-1], *then*
// free S.  Freeing S alone won't free each S[i].  
if ( !success )
{
  while ( i-- )
  {
    free( S[i] );
   }
  free( S );
  // bail out here
}

// for each S[i], allocate S[i][j].  
for ( size_t i = 0; success && i < m; i++ )
{
  for ( size_t j = 0; success && j < m; j++ )
  {
    S[i][j] = calloc( m, sizeof *S[i][j] );
    success = (S[i][j] != NULL );
  }
}

// Same deal - if any S[i][j] allocation failed, free all S[i][0] through
// S[i][j-1], *then* free all S[0] through S[i], *then* free S.  
if ( !success )
{
  do
  {
    while ( j-- )
      free( S[i][j] );
    free( S[i] );
  } while ( i-- );
  free( S );
  // bail out here
}

At this point, you've allocated enough memory to store m x m x m elements; index as you would any 3D array, S[i][j][k]. Unlike a 3D array, individual rows are not adjacent in memory - you wind up with something that looks like this:


   int ***       int **               int *                   int 
  +---+         +---+                +---+                   +---+
S:|   | ------> |   | S[0]   ------> |   | S[0][0] --------> |   | S[0][0][0]
  +---+         +---+                +---+                   +---+
                |   | S[1]           |   | S[0][1]           |   | S[0][0][1]
                +---+                +---+                   +---+
                 ...                  ...                     ...
                +---+                +---+                   +---+
                |   | S[m-1]         |   | S[0][m-1]         |   | S[0][0][m-1]
                +---+                +---+                   +---+

S points to a 1500-element sequence1 of int **; each S[i] points to a 1500-element sequence of int *; and each S[i][j] points to a 1500-element sequence of int.

Advantage - no single chunk of memory is that big (5 to 10 Kb, depending on pointer sizes).

Disadvantage - rows are not adjacent in memory, so you can't just "walk" through the whole array with a single pointer, and you can't copy or serialize the array in a single memcpy or fwrite call.

You want to be careful to roll back any partial allocations in case of a failure - just freeing S won't free memory you allocated for each S[i] or S[i][j].

When you're done, you'll need to deallocate in the reverse order that you allocated:

// free in reverse order of allocation
for ( i = 0; i < m; i++ )
{
  for ( j = 0; j < m; j++ )
    free( S[i][j] );
  free( S[i] );
}
free( S );

Again, this assumes your system can support upwards 16 GB of virtual address space (i.e., 64-bit). If not, you won't be able to build structures this large, period.


  1. I'm deliberately using the term "sequence" instead of "array" here, since none of S, S[i], nor S[i][j] are arrays as such. Each of those items is a pointer, not an array.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Thanks but when u mean if(!S) { // memory allocation failure, bail out here } and then work with S? In S array using for i give values like that... S[ 1] [ 1] [ 1]=2,... S[ 1][ 1][ 2]=8... and if a statment is false it stops(e.g. until S[1][1][8]=x and continue to S [2] [2][1].....to S[m][m][1]... how i can use this mehod that u say? – Nakos Kotsanis Oct 01 '17 at 01:37
  • i dont know if its possible(from StackOverFlow system) to post the code here as a comment here to understand my problem 100%... – Nakos Kotsanis Oct 01 '17 at 01:39
  • @NakosKotsanis: The code is correct and answers the question in the title. If you have a different question, please read [ask] and ask a new question. – too honest for this site Oct 01 '17 at 01:49
  • I'm sure that the code is correct but i really dont understand how to use this that @JohnBobe says... Except from the title there is a description that explains the problem. If the fact that i asked for more details from John because i didnt get it how to use this for my case is forbidden then why there is the "description field" and the potentiality to reply for more details?....Anyway you know better chief ;) – Nakos Kotsanis Oct 01 '17 at 02:04
  • @NakosKotsanis: In the body of the `if’ statement you would log an error and return (hence, “bail out”); the remainder of the code is only executed if the allocation is successful. – John Bode Oct 01 '17 at 02:04
  • Thanks again John but when I'm trying this memset below that if doesnt work, Can i pass it in this if? – Nakos Kotsanis Oct 01 '17 at 02:06
  • @NakosKotsanis: see my edit. `calloc` initializes all elements to 0, so you don’t need the separate `memset` call. – John Bode Oct 01 '17 at 02:16
  • I'm getting all the time the message "Fatal: unable to allocate array" and program stop working.... – Nakos Kotsanis Oct 01 '17 at 02:35
  • @NakosKotsanis: Askers are expected to understand an answer. If you don't, maybe you lack necessary basics. In fact your question will be answered easily reading good C book. – too honest for this site Oct 01 '17 at 02:55
  • @NakosKotsanis: 1500^3 `int`s is on the order of 12.5 Gb - you may not be able to allocate that much memory in a single chunk. – John Bode Oct 01 '17 at 12:32
  • @NakosKotsanis: See my edit. – John Bode Oct 02 '17 at 22:03
0

There are multiple issues with your code:

VLAs

Your array is a Variable-length array. This means that the array will most likely be allocated on the stack, which is limited in size (on linux the default is 8192 KiB, if thats the used system). Assuming sizeof(int) == 4, this space is is exhausted with m = 128. For m >= 128 you will get a segmentation-fault, as the accessed memory-areas are beyond the boundaries of the stack and thus the address of (most likely) unallocated heap-memory will be accessed.

Memory consumption

For m = 128 the array will consume 8 MiB, which isn't that large considering that even a usual 32-bit OS should be capable of handling a total of 4GiB of memory. But the memory-consumption grows by the power of 3. For m = 1500, a total of ~12.6 GiB will be used (1.35e10 bytes to be precise). That's way beyond the size of the stack, and might even cause problems if the memory is allocated on the heap. The above mentioned 32bit-system as an example will choke on this (special cases like PAE ignored).

Summary

If you want to support values beyond 127 for m, you'll have to allocate the memory on the heap. This will push the limit to match the size of memory that can be handled by the provided system. All the above calculations are rough estimates that don't take special cases into account and shouldn't be taken literal. They should do to get an impression of the upper bound of what can be handled though.