How to limit the size allocated memory? - c

While studying pointers I found that if I allocate memory for a 2 digit int I can give that int a higher value. Can someone explain me why it works like that and how to work around it?
Here is the code:
int *p;
p = (int *) malloc(2*sizeof(int));
p = 123456;

First of all, Please see this discussion on why not to cast the return value of malloc() and family in C..
That said, here, you're just overwriting the pointer returned by malloc(). Don't do that. It will cause memory leak. Also, if you try to dereference this pointer later, you may face undefined behavior, as there is no guarantee that this pointer points to a valid memory location. Accessing invalid memory leads to UB.
Finally, to address
I allocate memory for a 2 digit int [...]
let me tell you, you are allocating memory to hold two integers, not a two digit integer. Also, to store the integer values into the memory area pointed by the pointer, you need to dereference the pointer, like *p and store (assign) the value there, like *p=12345;.
malloc() allocates memory of the size of bytes passed as it's argument. Check the sizeof(int) (and 2*sizeof(int), if you want) to make it more clear.
Regarding this, quoting C11, chapter
void *malloc(size_t size);
The malloc function allocates space for an object whose size is specified by size [...]
So, here, malloc() returns a pointer with the size of two integers (i.e., capable of holding two integer values), not two digits or bytes.
Also, it's always a good practice to check the success of malloc() before using the returned pointer to avoid the possible UB by dereferencing NULL in case of malloc() failure.

if i allocate memory for a 2 digit int i can give that int a higher value.
No, you cannot. You have allocated memory for two ints, with full int range. Standard guarantees at least five digits (215-1), but on most modern systems you are safe with eight digits (231-1).
Back to your question, there is no way in C to ensure that your program does not write past the end of the memory that it allocates. It is the responsibility of your program to not do that, including any checks it must perform in order to catch potentially unsafe access.
This is called undefined behavior. The system may crash when you access memory past the end of the allocated area, but it does not have to.

allocate memory for a 2 digit int
malloc(2*sizeof(int)) allocates memory for two integers, not for a single two-digit integer.

you do not need the cast in the first place
You are allocated memory for two integers - typically 32 bits each
You are giving a pointer the value 123456
Perhaps reread the book

Related

Compatibility of data size while using malloc()

I recently studied about malloc() in C with declaration as follows:
void *malloc(size_t size)
where size_t is unsigned int and size defines the no. of bytes to be reserved.
Question is that on my system float values occupy 4bytes of memory. So if i make memory pointer(of float type) using malloc of 2bytes,
float *p;
p = (float *)malloc(2);
then how come it does not give any error? Because what i think is that float data required 4 bytes so if i issue only 2 bytes to it then it may lead to some data loss.
or is it that i m understanding malloc() incorrrectly?
In the example you give, if you only allocate 2 bytes for a float * and then attempt to write to that location by dereferencing the pointer, you'll be writing to memory that hasn't been allocated. This results in undefined behavior. That means it might work, it might core dump, or it might behave in unpredictable ways.
If you want to allocate memory for one or more floats, you would do it like this:
// allocates space for an array of 5 floats
// don't cast the result of malloc
int arrayLen = 5;
float *f = malloc(sizeof(float) * arrayLen);
You're encountering an implementation-specific result of the requirements of the C Standard:
7.22.3 Memory management functions
The order and contiguity of storage allocated by successive calls to
the aligned_alloc , calloc , malloc , and realloc functions
is unspecified. The pointer returned if the allocation succeeds is
suitably aligned so that it may be assigned to a pointer to any type
of object with a fundamental alignment requirement and then used to
access such an object or an array of such objects in the space
allocated (until the space is explicitly deallocated).
In order to provide storage "suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement", an implementation has to return memory from malloc() et al at specific offsets that are multiples of the most restrictive alignment requirement for the system. That's usually something like 8 or 16 bytes.
Given that each and every block returned has to be aligned that way, most implementations internally create blocks of memory in multiples of the alignment requirement.
So if your system has an 8-byte alignment requirement, your malloc() implementation is likely to actually give you an 8-byte block of memory even though you requested two bytes. Likewise, ask for 19 bytes and you'll likely get something like 24 in reality.
It's still undefined behavior to go beyond what you asked for, though. And undefined behavior does unfortunately include "works just fine".
This can be problematic if you try to use that pointer -actually the pointer is fine, it's the allocated memory it points to that's too small-, the reason the compiler doesn't recognize it as an error is the fact that the pointer isn't "aware" of what it points to , actually pointers are variables that contain memory addresses, so basically they're just a number, and in most cases ( as user694733 pointed out) the size of the pointer is the same whether it points to a short or a float.
what the compiler sees is a cast from (void*) to (float*) and to the compiler it's a totally valid cast.
Your question has actually nothing to do with the malloc, but rather to the data casting. In this case you have casted the bytes located starting from the address returned by malloc to float. Thus, if you later say *p = 0.0f; you will actually write 4 bytes to the mentioned memory area, but only 2 bytes are ligal to you to use since you have allocated only 2 bytes. Therefore, your code will compile and run with memory corruption (this either will result in crash, or in an unexpected runtime behavior later)

regarding memory allocated using malloc() [duplicate]

int *ptr = malloc(sizeof(char));
*ptr = 100000;
printf("%d\n", *ptr); // 100000
Shouldn't that only allocate enough memory for a char, i.e. 1 byte? Therefore shouldn't the largest number be 255?
How does it still print 100000?
Update
Thanks for the answers. If it overwrites the next bytes, how does C then know that this number is larger than one byte, and not just look in the first byte?
Because C has no range-checking of memory. It allocates a byte, and then your assignment via the pointer overwrites it and the next three bytes. If you had allocated another bit of memory right after the first malloc, but before the assignment, you might have overwritten part of the heap (depending on how your malloc works).
This is why pointers can be very dangerous in C.
The %d in the format statement (plus the type of the variable) tells the compiler you are looking at an int, and accesses all four bytes.
Note that if you really had assigned the value to a char, e.g. char *ptr; *ptr = 100000;
then with some compilers (and assuming plain char is treated as signed but default) it would have printed out -96, not 255 (or 127). This is because the compiler doesn't automatically limit the value to the highest value that can fit (127 in a signed char, 255 in an unsigned char), but instead it just overflows. Most compilers will complain that you are trying to assign a constant value that overflows the variable.
The reason it is -96, is that 100000 % 256 is 160, but as a signed char it is output as -(256-160).
Short answer: you're invoking undefined behaviour by writing to memory that doesn't belong to you, so you never know what you might get. It might just work, it might crash, or it might do any number of other things. In this case, you're putting an int at the position that ptr references, which writes the first byte of the int into the 1-byte allocated region, and smashes whatever lived in the following three bytes.
When you read the value back with the %d format specifier, printf reads sizeof(int) bytes from memory to print them as an int. If you want to output just the value of one byte, you need to do something like:
printf("%d\n", *(char*)ptr);
That is, tell the compiler that ptr refers to a char, then get that char value, which is promoted to an int in an argument list and subsequently output correctly by the %d specifier.
This is 3 byte overflow. Overflow like this from stackoverflow logo, but on a heap not stack.
The simplest answer would be: it's not guaranteed to work.
Basically, you are corrupting the memory around the pointer.
To answer your updated question; C "sees" *ptr i.e. contents of ptr where ptr points at an integer. So it reads an integer from that ptr. It has already forgotten that you only allocated one character. The two parts (allocation and then access) aren't linked by anything you've expressed in your code.
Generally, malloc will allocate memory with greater granularity than a single byte, so your request for a single byte will reserve a memory space rounded up to the nearest 8 bytes or something. You then write to this space, blithely going right past what you've reserved. Then you dereference the pointer, bringing back an int, and hand that to printf which happily prints it out.
As others have said, depending on this behavior is a bad, bad idea. Allocate exactly what you need and don't overrun your buffers.

Few doubts about pointers in C

1) to initialize a pointer I use:
int number, *Pnumber;
Pnumber=&number;
number=10;
Am I doing this right?
what about:
int *Pnumber;
*Pnumber=10;
When I compile it, I get:
RUN FAILED (exit value 1, total time: 858ms)
btw. do I need to use free(Pnumber) to free the memory?
Am I doing this right?
Yes, you are.
what about:
`int *Pnumber;
*Pnumber=10;`
Pnumber is an unitialized pointer. Dereferencing this pointer leads to an undefined behavior. Pnumber must point to an allocated memory (either to a variable or a dynamically allocated memory area).
btw. do I need to use free(Pnumber) to free the memory?
As long as you don't use malloc, don't use free.
In the first version you point the pointer Pnumber to memory that has already been allocated and thus you may change the value pointed to by the pointer. This version is correct. In the second version you never specify what is the pointer pointing to(it remains uninitialized) and thus when you try to access the memory this will cause an error. So the second version is not correct.
Your first approach is right.
But this wrong:
int *Pnumber;
*Pnumber=10;
Because the pointer doesn't point to valid memory whereas in the first approach it does.
The first one is correct
In the second you are missing pointing the pointer to a memory space.
The pointer is an address so
If we have
int *p;
That means p is an address
and *p is the content of the memory address.
so the pointer should be pointed to a memory space before you fill the memory with
*p = 5;
if you use a Pointer you "point a variable like you did:
int number, *Pnumber;
Pnumber=&number;
number=10;
the advantage of the Pointer is that you save memory to your Program so if you want to change the value of number which is an integer 32bit you can use
*Pnumber = 10;
here you're using integer but if you use a array of them or double or float it a lot of memory and that why it better for you to save the address of the variable in 32 bit in 32bit OS architecture always with pointer in doesn't matter what type you'RE pointing at

realloc in C — exact behaviour and uses

Reading some literature, I was able to grasp that realloc takes in a void pointer and a size variable and re-allocates the memory of the block the void pointer points to.
What will happen if realloc is called on an integer pointer (int *)
with a size of character? And vice versa.
What can be a possible application of this? (An example would definitely help.)
The realloc() function is the all-in-one memory management system.
If called with a null pointer and a non-zero size, it allocates memory.
If called with a valid pointer and a zero size, it frees memory.
If called with a valid pointer and a non-zero size, it changes the size of the allocated memory.
If you call realloc() with an invalid pointer — one which was not obtained from malloc(), calloc() or realloc() — then you get undefined behaviour.
You could pass realloc() an integer pointer to an allocated space of sizeof(char) bytes (1 byte), but you'd be in danger of invoking undefined behaviour. The problem is not with realloc(); it is with the code that was given an unusable integer pointer. Since only 1 byte was allocated but sizeof(int) is greater than 1 (on essentially all systems; there could be exceptions, but not for someone asking this question), there is no safe way to use that pointer except by passing it to free() or realloc().
Given:
int *pointer = malloc(sizeof(char));
you cannot do *pointer = 0; because there isn't enough space allocated (formally) for it to write to. You cannot do int x = *pointer; because there isn't enough space allocated (formally) for it to read from. The word 'formally' is there because in practice, the memory allocators allocate a minimum size chunk, which is often 8 or 16 bytes, so there actually is space after the one byte. However, your are stepping outside the bounds of what the standard guarantees, and it is possible to conceive of memory allocators that would hand you exactly one byte. So, don't risk it. An integer pointer to a single byte of allocated memory is unusable except as an argument to the memory allocation functions.
The first argument to realloc() is a void *. Since you're going to have a prototype in scope (#include <stdlib.h>), the compiler will convert the int * to a void * (if there's anything to do for such a cast), and as long as the space pointed at was allocated, everything will be fine; realloc() will change the allocation size, possibly returning the same pointer or possibly returning a different pointer, or it will release the space if the new size is zero bytes.
There is a vitally important requirement to non-NULL pointers that you pass to realloc: they must themselves come from a call to malloc, calloc or realloc, otherwise the behavior is undefined.
If you allocate a chunk of memory sufficient to store an int and then realloc for a char, you will always get back the same pointer, because sizeof(char) is less than or equal to the sizeof(int):
int* intPtr = malloc(sizeof(int));
int* otherPtr = realloc(intPtr, sizeof(char));
// intPtr == otherPtr
If you try it the other way around, you will almost certainly get back the same pointer as well, because memory allocators rarely, if ever, parcel the memory to chunks smaller than sizeof(int). However, the result is implementation-dependent, so theoretically you may get back a different address.
As far as the utility of any of the above exercises goes, it is not useful: realloc has been designed with the intention to help you manage variable-sized arrays, simplifying the code for growing the size of such arrays, and potentially reducing the number of allocations and copying. I do not see a reason for realloc-ing a scalar.
The type of the first parameter of realloc is void *, as you said yourself. So the function argument that you pass is converted to a void pointer, which is an implicit and safe conversion.
It's the same as if you called a function with a long int parameter with an int argument, essentially.
Realloc takes the size in bytes. If you do
int* a= malloc(sizeof(int));
and then
a=realloc(a,1);
of course a will now not be big enough for an int type and writing an int in it will give you odd behavior.
As stated by dasblinkenlight, realloc doesn't make sense for a scalar.
In your example:
int * a = malloc(sizeof(int));
int * b = realloc(a,sizeof(char));
Would result in a == b, simply because sizeof(char) < sizeof(int) and there is no reason for moving the data to a new location.
The difference is, that after the realloc you are writing your int to unallocated space, as you decreased the allocated space using realloc. Here this is only of theoretical relevance. Because of alignment it is very unlikely, that the os is reusing the freed memory. But you shouldn't rely on that. This is undefined behavior.
It could become relevant, if you resize the space of a long int to an int. This depends on your architecture.
Writing to unallocated space is like laying a time bomb and not knowing when it will explode. You should only read from / write to allocated space.

Dynamic memory allocation questions with realloc and calloc

See the following function:
int go(void) {
int *p, *q;
p = calloc(10,sizeof(int));
q = realloc(p, 20 * sizeof(int));
<<X>>
}
Assuming that both memory allocation function calls are successful, which of the following statements are true at the point marker <<X>>.
The values of p and q are the same.
p points to 10 integers each with the value of 0.
q points to at least 80 bytes of memory.
This question is in my C test paper. Except for (2) which is obviously true. I'm quite confused about (1) and (3). Can anybody explain me this?
Check out the documentation. Specifically (emphasis added):
RETURN VALUE
Upon successful completion with a size not equal to 0, realloc()
returns a pointer to the (possibly moved) allocated space. If size is
0, either a null pointer or a unique pointer that can be successfully
passed to free() is returned. If there is not enough available memory,
realloc() returns a null pointer and sets errno to [ENOMEM].
So, the p and q may be the same (if realloc is able to resize the existing block of memory), but it's not guaranteed (and so you shouldn't rely on it).
According to the C standard, an int must be at least 16 bits (2 bytes), so sizeof(int) is at least 40, so (3) is not necessarily true.
As Brendan said, (1) is not necessarily true (and probably not true).
In C, generally an "int" is 4 bytes, so (3) should be true. It is true on all systems that I know of, although I'm not positive that the C standard says that an "int" must be four bytes long.
1) both p and q are pointers. Look up documentation on what realloc does for the answer. 3) That statement is ambiguous. In C, the value of pointers are typically scalar addresses to a byte location. The size of the memory block allocated is unknown. The type of the pointer is used to determine the size of a stride when doing pointer arithmetic, but if you allocated a buffer of a multiple size of some type, that is still unknown from the variable itself.
Chech these link.These says that 1 may be true or false its like can't say http://www.thinkage.ca/english/gcos/expl/c/lib/reallo.html
Hope these information helps you as many people already explained about 3rd case
1 is true or false
because q points to the reallocated memory. This may be the same as "p" if the old block of memory could be grown (or shrunk) to the new size; otherwise, it will be a different block. The space begins at an alignment boundary that is suitable for storing objects of any data type. If memory cannot be acquired or if an argument is improperly specified, the NULL pointer is returned.
The amount of memory pointed to by q depends on the size of the int type, which might not be four bytes. Statement one is also not necessarily true. From the realloc(3) man page on my system:
If there is not enough room to
enlarge the memory allocation pointed to by ptr, realloc() creates a new
allocation, copies as much of the old data pointed to by ptr as will fit
to the new allocation, frees the old allocation, and returns a pointer to
the allocated memory.
As this is an exam question, we have to refer to the specification. All three are to be considered false.
realloc can return a pointer that is different to p.
realloc can will free the memory pointed to by p if the newly allocated space is in a different location. This means that p may still point to ten zeros, but this is not what the specification says.
As explained well in other answers, we don't know the size of an int (that is why we use sizeof(int)).

Resources