0

Whenever I see malloc in someone else's code, it typically uses sizeof(short) or sizeof(double) etc. to help define the size of memory to be allocated. Why do they not just replace those expressions with 2 or 8, in those two examples?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Karnivaurus
  • 22,823
  • 57
  • 147
  • 247

3 Answers3

5

It makes the code easier to port.

In general there are compiler options which allow you to say how data is to be alligned in a struct. The size of a double may vary between platforms. By consistantly using the data type, you reduce the occurance of some types of size mismatch errors.

I think it is a better practice to use the variable name instead of the data type for the size of piece.

float Pi = 3.14f;

float *pieArray = (float *) malloc(sizeof (Pi) * 1000);

Personally I would prefer this method.

typedef float Pi;

Pi *piArray = new Pi[1000];

// use it

delete[] piArray;

new/delete should be preferred over malloc/free in most cases.

EvilTeach
  • 28,120
  • 21
  • 85
  • 141
  • 1
    Note that `sizeof` is an operator, not a function, and the parentheses are only required if the operand is a type name; `sizeof Pi` will work just as well. – John Bode Mar 19 '15 at 18:14
  • 2
    Yet, in this case, if you change the type of `Pi` you still have a problem. You're better off using `sizeof *pieArray`. Yes, you could still mismatch `Pi`, but from a perspective of performing operations on the array, you're in better shape. Also, don't case the return value of `malloc` in C – Ed S. Mar 19 '15 at 18:16
  • Yep. i Generally don't worry about it and use them all the time. – EvilTeach Mar 19 '15 at 18:16
  • @ed. Personally i would use new syntax instead of malloc, and typedef Pi as a data type, then use the data type rather than float in the second statement. Never the less, the op is using malloc, so I did too. – EvilTeach Mar 19 '15 at 18:17
  • 1
    Well, yes, the OP doesn't seem to understand the differences between C and C++. We should assume C here. My point about using the type of the array still stands. There's no good reason not to. – Ed S. Mar 19 '15 at 18:18
  • To further nitpick... if we're going to add a C++ example, use `std::vector` and be done with it – Ed S. Mar 19 '15 at 18:30
  • Another point is maintenance. If the contents of the structure change, then all the hard coded allocation quantities must be reviewed. Without hard coded values, this review is not necessary. – Thomas Matthews Mar 19 '15 at 18:34
  • @ed. Nah. That is beyond the scope of the Ops question. – EvilTeach Mar 19 '15 at 18:34
  • using the name instead of type is a problem if the compiler don't know the length. You then get the length of the pointer to the variable. – fhtuft Mar 19 '15 at 18:38
  • 1
    I'm not convinced that clearing up obvious confusion is something to be avoided, but he'll have to figure it out eventually. You also fail to explain *why* `new/delete` is preferred in C++. – Ed S. Mar 19 '15 at 18:38
1

The most portable and maintainable way to write a malloc call in C is:

T *p = malloc( N * sizeof *p );

or

T *p;
...
p = malloc( N * sizeof *p );

where T is any arbitrary type and N is the number of objects of that type you want to allocate. Type sizes are not uniform across platforms, and the respective language standards only mandate minimum ranges of values that non-char types must be able to represent. For example, an int must represent at least the range [-32767...32767], meaning it must be at least 16 bits wide, although it may be (and often is) wider. For another example, struct types may have different amounts of padding between members depending on the platform's alignment requirements, so a struct foo type may take up 24 bytes on one platform and 32 on another.

The expression *p has type T, so sizeof *p gives the same result as sizeof (T), which is the number of bytes required to store an object of type T. This will always give you the right number of bytes to store your object (or sequence of objects), regardless of platform, and if you ever change T (from int to long, for example), you don't have to go back and change the arguments to the malloc call.

Note that you shouldn't use malloc or calloc in C++ code; you should use a standard container like a vector or map that handles all the memory management for you. If for some reason a standard container doesn't meet your needs, use the new operator to allocate a single object of type T and new [] to allocate an array of objects.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Neither the size of a double or a short is fixed by the c++ standard. Note that for a double, it doesn't even have to be an IEEE754 floating point type. In this respect c++ differs from Java. So it would be a poor idea to hardcode the size.

And use new / new[] and delete / delete[] in C++.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    Where does it say that? Under [expr.sizeof] it only defines size of `char`, and `signed char` and `unsigned char` and says the size of other fundamental types are implementation-defined. –  Mar 19 '15 at 18:02
  • 2
    "A double is fixed at 64 bits by the standard so has a sizeof 8" – um, I don't think either of that is true. Floating-point types have *minimal* precision and range requirements, but it's not fixed. Also, a 64-bit number can have any `sizeof` less than or equal to 8 – since `CHAR_BIT` is defined to be *at least* 8, but it could be more. (also, if we consider the ability to add padding bits, then the result of sizeof could vary in an even wider range.) – The Paramagnetic Croissant Mar 19 '15 at 18:22
  • Wikid this as the comments add interest – Bathsheba Mar 19 '15 at 18:32