4

I am relatively new to 'C' and would appreciate some insight on this topic.

Basically, I am trying to create a 16 MB array and check if the memory content is initialized to zero or '\0' or some garbage value for a school project.

Something like this:

char buffer[16*1024*1024];

I know there is a limit on the size of the program stack and obviously I get a segmentation fault. Can this somehow be done using malloc()?

trincot
  • 317,000
  • 35
  • 244
  • 286
  • 1
    Note: Many systems today use a 32-bit `int`, so `16*1024*1024` is not an issue. Take care on some CPUs (like some embedded devices) where 16-bit `int` still occur and `16*1024*1024` overflows. Code could use `16L*1024*1024` (added L). Of course, using a 16 MB array is unlikely on a 16-bit `int` device. – chux - Reinstate Monica Jun 10 '15 at 21:07
  • @chux: Can you please elaborate a little about what 'L' stands for? Its general purpose usage? That would be great. – absolut_red Jun 10 '15 at 21:13
  • 1
    `L` makes a constant at least type `long`. `long` integers have at least a range of about -2,000,000,000 to +2,000,000,000 range. (-power(2,31)+1 ... power(2,31)-1). – chux - Reinstate Monica Jun 10 '15 at 21:16

4 Answers4

4

You can initialize the memory with malloc like so:

#define MEM_SIZE_16MB   ( 16 * 1024 * 1024 )

char *buffer = malloc(MEM_SIZE_16MB * sizeof(char) );
if (buffer == NULL ) {
    // unable to allocate memory. stop here or undefined behavior happens
}

You can then check the values in memory so (note that this will print for a very very long time):

for (int i = 0; i < MEM_SIZE_16MB; i++) {
    if( i%16 == 0 ) {
        // print a newline and the memory address every 16 bytes so 
        // it's a little easier to read
        printf("\nAddr: %08p: ", &buffer[i]); 
    }
    printf("%02x ", buffer[i]);
}
printf("\n");  // one final newline

Don't forget to free the memory when finished

free(buffer);
rost0031
  • 1,894
  • 12
  • 21
  • Do we have to explicitly free this allocated memory? I thought when the program is done executing, the memory is automatically released back to the OS. Correct me if I am wrong. – absolut_red Jun 10 '15 at 20:22
  • Yes, it is in this case but it's good practice to do in general. For any non-trivial code, a program will usually run for a while so: 1 malloc = 1 free. Since OP is clearly new to C, better start off on the right track right away. – rost0031 Jun 10 '15 at 20:25
  • 1
    `printf("\nAddr: 0x%08x: ", (unsigned int)(&buffer[i]));` warning: cast from pointer to integer of different size. Is it more convenient to use a %p? – absolut_red Jun 10 '15 at 21:00
  • @Absolut_Red: yes, that's a better way. I'll edit to reflect that. – rost0031 Jun 10 '15 at 21:12
  • Also the '0x' prefix doubles up. If that could be taken off – absolut_red Jun 10 '15 at 21:25
2

Sure:

int memSize = 16*1024*1024;
char* buffer = malloc( memSize );
if ( buffer != 0 )
{
    // check contents
    for ( i = 0; i < memSize; i++ )
    {
        if ( buffer[i] != 0 )
        {
            // holler
            break;
        }
    }


    free( buffer );
}
donjuedo
  • 2,475
  • 18
  • 28
2

Yes, you will probably need to do this using malloc(), and here's why:

When any program (process ... thread ...) is started, it is given a chunk of memory which it uses to store (among other things ...) "local" variables. This area is called "the stack." It most-certainly won't be big enough to store 16 megabytes.

But there's another area of memory which any program can use: its "heap." This area (as the name, "heap," is intended to imply ...) has no inherent structure: it's simply a pool of storage, and it's usually big enough to store many megabytes. You simply malloc() the number of bytes you need, and free() those bytes when you're through.

Simply define a type that corresponds to the structure you need to store, then malloc(sizeof(type)). The storage will come from the heap. (And that, basically, is what the heap is for ...)

Incidentally, there's a library function called calloc() which will reserve an area that is "known zero." Furthermore, it might use clever operating-system tricks to do so very efficiently.

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
2

Strictly speaking, code can not check if buffer is not zeroed without risking undefined behavior. Had the type been unsigned char, then no problem. But char, which may be signed, may have a trap value. Attempting to work with that value leads to UB.

char buffer[16*1024*1024];
// Potential UB
if (buffer[0])  ...

Better to use unsigned char which cannot have trap values.

#define N (16LU*1204*1204)
unsigned char *buffer = malloc(N);
if (buffer) {
   for (size_t i = 0; i<N; i++) {
     if (buffer[i]) Note_NonZeroValue();
   }
}

// Clean-up when done.
free(buffer);
buffer = 0;

The tricky thing about C is that even if char does not have a trap value, some smart compiler could identify code is attempting something that is UB per the spec and then optimize if (buffer[0]) into nothing. Reading uninitialized non-unsigned char data is a no-no.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Your code does check if buffer is zeroed without risking UB so the first sentence needs to be edited. Also, C11 is that it's OK to read a trap representation via a character type so I think the `char *` version was OK – M.M Jun 10 '15 at 00:12
  • @Matt McNabb scanned C11 and did not see clearly where a `char` trap was OK. Any details appreciated. – chux - Reinstate Monica Jun 10 '15 at 00:35
  • @Matt McNabb http://stackoverflow.com/a/6725981/2410359 and https://groups.google.com/forum/#!topic/comp.std.c/rRfT9fa6ga8 may be useful. in the short term. Will need to dig deep into C11 later. – chux - Reinstate Monica Jun 10 '15 at 01:23
  • C99+TC2 (N1124) and C11 both clearly say in 6.2.6.1/5, " If the stored value of an object has such a representation **and is read by an lvalue expression that does not have character type**, the behavior is undefined." So it doesn't matter whether `char` has trap representations or not; even if it does, reading them does not cause UB. Although I guess you could argue that it also doesn't say what happens when a trap representation of `char` does get read, and anything not defined is undefined. – M.M Jun 10 '15 at 01:45
  • C11 adds in the clause "`signed char` shall not have any padding bits". It can still have the trap representation negative zero, so I take 6.2.6.1/5 to say that reading the negative zero does not , in itself, cause UB; but then we refer to the rules about negative zeros in 6.2.6.2 to see whether what is subsequently done with the value triggers UB or not. – M.M Jun 10 '15 at 01:52
  • @Matt McNabb Suspect your understanding is closer to the mark than mine. IAC, reading unitalicized data, as that is OP's issue here, is, at least, not a good programming paradigm. – chux - Reinstate Monica Jun 10 '15 at 01:58
  • No argument there, although it seems OP's been asked to do it for an assignment! Also, sometimes I wonder if more man-hours have been spent discussing trap representations on the internet than actually coding on machines that have them.... – M.M Jun 10 '15 at 01:59