4

Why can't I store a large integer in this allocated block of memory?

int *dyn = malloc(16);
*dyn = 9999999999;

printf("%lli\n", *dyn);

free(dyn);

At compile-time, GCC warns me that an integer overflow will occur. And sure enough, when printed out, it has overflowed.

Why can't I use the entire block of memory to store a single value?

joe.
  • 75
  • 2
  • 5
    Because all you have is a pointer to a single `int` value. It doesn't matter how much memory it points to, as allocations are done at run-time and the literal value `9999999999` is handled by the compiler at compile-time. – Some programmer dude Feb 18 '20 at 11:35
  • 2
    Furthermore, since `*dyn` is pointing to an `int`, using the format specifier `%lli` is wrong. Mismatched format specifier and argument type leads to *undefined behavior*. – Some programmer dude Feb 18 '20 at 11:36
  • 1
    @rootkonda In C you [should not cast the result of `malloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). Also 16 bytes should be more than enough for a 4-byte `int` or even an 8-byte `long long`. And as a pointer variable `dyn` *does* store the address returned by `malloc`, and the OP is correctly using `*dyn`. – Some programmer dude Feb 18 '20 at 11:45
  • Usually you should do `int *dyn = malloc(sizeof(*dyn) * length);` to avoid mismatching memory spaces. This can be a problem when you do something like `dyn[5]` for example. – RobertS supports Monica Cellio Feb 18 '20 at 12:53

5 Answers5

6

*dyn = 9999999999; does not instruct the computer to use all the memory that was allocated for dyn to store the value 9999999999.

In C, dyn has a type. The type is “pointer to int”. Then *dyn has type int, which has a specific, fixed number of bits. It does not have a type meaning “all the memory that was allocated for dyn”.

Since *dyn is an int, *dyn = 9999999999; tells the computer to put 9999999999 into an int. Since 9999999999 is too big for an int in your C implementation, an overflow occurs.

We can program computers and design programming languages to manage integers of arbitrary sizes. Some languages, such as Python, do this. However that requires extra software, particularly software that has to do some variable amount of work when the program is running in order to handle whatever sizes of numbers come along. C is designed to be an elementary language. It works with objects of specific sizes and generally translates C code to fixed amounts of work in processor instructions. These provide building blocks for programmers to build bigger software. So, in C, int objects have fixed sizes. Allocating 16 bytes of memory provides space for several int objects, but it does not provide a big integer object.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
5

The size of int is usually 4 bytes (32 bits). And, it can take 2^32 distinct states from -2147483648 to 2147483647. So when you try to store this *dyn = 9999999999; , integer overflow occurs. It is not pointing to the memory location, it is pointing to the value of that variable.

Himanshu Jain
  • 334
  • 2
  • 12
  • When using *dyn = 9999999999; directly like this, it points to a memory location but saves 9999999999 as its value. Pointers in C can take address of other variables by using the '&' symbol. For more detail on pointers in C, you can refer: https://www.programiz.com/c-programming/c-pointers – Himanshu Jain Feb 18 '20 at 11:48
  • dyn is pointing to a memory location. I don't understand how it could not be pointing to a memory location. `*dyn = 1;` stores a value in a memory location. Where else would it store the value? – user253751 Feb 18 '20 at 11:49
  • It treats *dyn as a first integer unit from the memory location pointed by dyn. As similar to arrays: int dyn[16]; dyn[0]=99999999999999; – Dr. Andrey Belkin Feb 18 '20 at 11:53
  • *"It is not pointing to the memory location, it is pointing to the value of that variable."* is incorrect. It shall be *"It is not pointing to the memory location of the pointer, it is pointing to the memory location of the pointed variable.*" – RobertS supports Monica Cellio Feb 18 '20 at 12:58
1

Why can't I use the entire block of memory to store a single value?

Because the size of int is almost certainly not 16 bytes, and when you de-reference a int pointer in the *dyn = 9999999999; expression, that access is limited to the size of int, which is likely 2^31 - 1.

Please note that the integer constant 9999999999 has a type too, which is dynamically determined by the compiler depending on the number's size. In this case, very likely long long. So the actual bug here is your attempt to do int x = 9999999999; which isn't the slightest related to malloc or pointers. It's a simple overflow.

To use numbers larger than 2.14 billion, you must use a 64 bit type instead. Use int64_t/uint64_t from stdint.h.

You cannot allocate 16 bytes, memcpy som value in there and then access the data through pointers to some arbitrary integer type. This is because of the somewhat dysfunctional C type system. Simplified explanation: the chunk of data returned from malloc has no type internally, until you store something there. Then it gets the type you used when storing, and all subsequent access have to use that same type too, everything else invokes undefined behavior according to "the strict aliasing rule".

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

dyn is an integer pointer (actually, pointing to a reserved memory of int array of 16 bytes). *dyn is an integer (first element from this int array). As similar to arrays:

int dyn[4];
dyn[0]=9999999999;

Assigning 9999999999 to int leads to a variable overflow, since int allows on modern platforms only [−2 147 483 648, +2 147 483 647] range (and at least [−32767, +32767]).

Dr. Andrey Belkin
  • 795
  • 1
  • 9
  • 28
0

9999999999 or better illustrated as 9,999,999,999 is not in the range of an int, to which dyn is pointing to, don´t matter how much memory malloc has allocated:

int *dyn = malloc(16);   // `dyn` points to an `int` object, don´t matter 
                         // if malloc allocates 16 bytes.
*dyn = 9999999999;       // Attempt to assign an out-of-range value to an `int` object.

An object of type int shall be allocated by 4 Bytes in memory by the most modern systems.

4 Bytes can hold a maximum of 2^(8*4) = 2^32 = 4,294,967,296 values.

Now you have the type of int which is equivalent to the type of signed int.

signed int can store positive and negative numbers, but since it can store positive and negative numbers it has quite a different range.

signed int has the range of -2,147,483,648 to 2,147,483,647 and so is the range of int.

So you can not hold 9,999,999,999 in an int object because the maximum value an int object can store is the value of 2,147,483,647.

If you want to store the value of 9,999,999,999 or 9999999999 in an object, use f.e. long long int, but not long int since long int can hold the same range of an int and an unsigned int:

long long int *dyn = malloc(16);   // `dyn` points to an `long long int` object.
*dyn = 9999999999;  // Fine, because 9999999999 is in the range of an `long long int` object.