5

In C when we use the calloc method; all the reserved memory will be initialized to 0.

Is there any way to initialize it with another value without iterating over all the values? For example:

int* example = calloc(100,sizeof(int));

This will create an array of 100 zero's, but I want this to be (for example) 100 ones.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Domien
  • 395
  • 5
  • 18
  • 6
    malloc it and call memset on the malloc'ed chunk – Petr Skocik Oct 16 '15 at 17:37
  • Suppose I got an initialized "object" of a struct ( and example will be of type struct* of course). Will this "object" be copied for each of the 100 memory locations? – Domien Oct 16 '15 at 17:46
  • Another example of the phrase "As we know" claiming something wrong. The memory is initialised with [**all bits zero**](http://port70.net/~nsz/c/c11/n1570.html#7.22.3.2p2) which is not necessarily the same as a `0`/`0.0` or a null pointer. `calloc`, like `memset` has no idea about the structure of the block. And C does not have _methods_. `calloc` is a _function_! – too honest for this site Oct 16 '15 at 17:46
  • You mean if 00000000 on a machine means for example the character 'a'. Then calloc will initialize everything to 'a'? – Domien Oct 16 '15 at 17:50
  • Okay. I understand it. Thank you all for the information. :) – Domien Oct 16 '15 at 17:53
  • 2
    1) please use `@` to address a commenter, otherwise ysour comment might get unnoticed. 2) see my answer. – too honest for this site Oct 16 '15 at 18:02
  • If we had access to the underlying memory system, for large sizes, code could initialize one page of memory to the desired value and map all other pages of the memory assignment to the _same_ page. So a less than O(n) solution for the moment. Later as code changes the values, the memory mapped pages would need to diverge, taking time. But this time is spread out over code run-time. This trick is used by many systems for the value of 0 (see [here](http://stackoverflow.com/questions/2688466/why-mallocmemset-is-slower-than-calloc?rq=1)). – chux - Reinstate Monica Oct 16 '15 at 19:00

3 Answers3

5

calloc as much as memset has no idea about the structure of the data stored in the allocated block. It is actually of little use to use memset with anything different from 0 on something other than an array of char type. Note that calloc is functionally malloc plus memset(..., 0), but might be significantly faster in some implementations.

According to the standard, calloc does not store 0, but sets all bits zero. This does not necessarily result in a float 0.0 or a null pointer constant, as they might have other binary representations. For integer types, however, 0 has all bits zero, so this works.

But only for the 0, because on most (if not all) modern platforms integer uses at least 2 bytes, so if you set byte-wise, you will touch different bytes of the same integer. Just try memset(..., 3), for 32 bit int you will read 0x03030303, for 64 bit 0x0303030303030303.

To set structured values of an allocated array, there is no way around using a loop:

// here we use int, but that can also be float or a struct
int *a = malloc(sizeof(*a) * 5);
if ( a != NULL ) {
    for ( size_t i = 0 ; i < 5 ; i++)
        a[i] = 1;    // for a struct use a compound literal or set per field

    ...
    free(a);
}

You should not worry about performance in the first place. The pattern above is very likely recognised by your compiler and replaced by highly optimised code which will be as fast (if not faster) as memset (but not calloc).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
4
int* example;
example=malloc(100*sizeof(int));    // allocate memory to store 100 int
if(example){
    memset(example,1,100*sizeof(int));  // initialize it with value 1
}

EDIT

Despite someone upvoted for the above code but (I made a mistake and now correcting it) - Above example is wrong .As from manpage -

The memset() function fills the first n bytes of the memory area pointed to by s with the constant byte c.

So , the above piece of code will not work as expected .

// allocate memory as you do 
for(int i=0;i<100;i++){
      example[i]=1;
}
 free(example);

This will do the work .

ameyCU
  • 16,489
  • 2
  • 26
  • 41
1

Let the compiler figure it out how to do it quickly by copying large chucks with memcpy() - certainly an optimized function call.

int *alloc_int_preset(int value, size_t count) {
  int *begin = malloc(sizeof *begin * count);
  if (begin && count) {
    count--;
    size_t n = 1;
    *begin = value;
    int *p = &begin[1];  // place to copy to
    while (count > 0) {
      size_t i = min(count, n);
      // perform memcpy() in ever doubling in size blocks
      memcpy(p, begin, sizeof *p * i);
      p += i;  // advance i `int`s
      n += i;  // advance i
      count -= i;
    }
  }
  return begin;
}

1st time through the loop, memcpy(&begin[1], begin, sizeof *p * 1)
2nd time through the loop, memcpy(&begin[2], begin, sizeof *p * 2)
3rd time through the loop, memcpy(&begin[4], begin, sizeof *p * 4)
4th time through the loop, memcpy(&begin[8], begin, sizeof *p * 8)

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I smell potential for UB. Also I suspect this is really faster than the `for` loop pattern. – too honest for this site Oct 16 '15 at 18:19
  • @Olaf Apply thy nose and try to find it. No UB. – chux - Reinstate Monica Oct 16 '15 at 18:20
  • It is not where you might think. You do not check the result of `malloc` (I just wrote "potential", not it is there) – too honest for this site Oct 16 '15 at 18:20
  • 1
    @Olaf I think `assert(begin)` will do that . – ameyCU Oct 16 '15 at 18:22
  • @ameyCU: Do you ship debugging versions of your code to end-customers? – too honest for this site Oct 16 '15 at 18:23
  • @Olaf I did not use `assert(begin)` right after the `malloc()` as that may falsely fire when `count == 0` and `malloc()` legitimately returns `NULL`. So the test is after `if (count) {`. – chux - Reinstate Monica Oct 16 '15 at 18:24
  • @Olaf Sorry , I don't quite understand that , was it a sarcasm or anything else ? If genuine i would say No . Please bear with me :) – ameyCU Oct 16 '15 at 18:27
  • @Olaf Yet easy enough to improve per your concern. – chux - Reinstate Monica Oct 16 '15 at 18:27
  • @chux: You should test `count` actually before `malloc`. The behaviour is implementation defined for `0` size. – too honest for this site Oct 16 '15 at 18:29
  • @ameyCU: It was. `assert` is a NOP unless `NDEBUG` is `#define`d. (but that would not be the first debug version shipped) – too honest for this site Oct 16 '15 at 18:30
  • @Oalf When `count == 0` and then maybe `malloc(0)`, OP has not identified the desired behavior in this corner case. IAC, the above answer does address the larger issue of offering a performance candidate that relies heavily on `memcpy()`. The "best" answer may be a platform specific decision point between using a [basic loop](http://stackoverflow.com/a/33176746/2410359) and then this answer for large `count`. – chux - Reinstate Monica Oct 16 '15 at 18:34
  • @Olaf Ohh , that's what you meant . – ameyCU Oct 16 '15 at 18:35
  • @chux: I very well doubt reading/writing from/to memory is faster than storing a register. It might be, for a `struct`, however. It is a good way to cache-trashing once the array becomes larger. To me it looks like preliminary optimisation at best. It certainly is harder to maintain. – too honest for this site Oct 16 '15 at 18:38
  • @Olaf With so many platforms that C runs on, board conclusions on performance readily fail. Benchmarking/Profiling helps. Of course the `for()` loop functions as needed and is easy to code/maintain - I am confident OP knows about that. OP is certainly seeking potential faster solutions and is willing to incur more maintenance, so maintenance is of secondary importance. – chux - Reinstate Monica Oct 16 '15 at 18:48