This question already has answers here:
C array size given by variable
(2 answers)
Closed 5 years ago.
I'd read that size specifier is mandatory while declaring an array if it is not explicitly initialized,
but the piece of code given compiles and runs successfully?
main()
{
int r;
scanf("%d",&r);
char array[r]; //memory is not allocated at compile as value of variable is not known
scanf("%s",array);
printf(array);
}
This is valid code that makes use of Variable-Length Array feature of C99.
As long as r is properly set by scanf, it is legal to use it in allocation of char array[r].
There are several issues that need to be addressed, though:
If scanf returns zero, r remains uninitialized. Using it for specify array size in a declaration would be illegal.
If scanf read a negative number, using it as array size would be illegal.
If scanf read a number that is too large for your system's automatic memory space, you would run into undefined behavior.
The last point is very important: your system may have enough memory for the array, but not enough space in the automatic memory (often called "stack") to allocate your array. This can result in a crash.
A better approach is to allocate your array dynamically with malloc, and free it once you are done with it.
Related
This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Writing to pointer out of bounds after malloc() not causing error
(7 answers)
Why is it that we can write outside of bounds in C?
(7 answers)
What happens if I try to access memory beyond a malloc()'d region?
(5 answers)
Why does int pointer '++' increment by 4 rather than 1?
(5 answers)
Closed 3 years ago.
I've been digging into memory allocation and pointers in C. I was under the impression that if you do not allocate enough memory for a value and then try to put that value in that memory cell, the program would either crash or behave incorrectly.
But what I get is a seemingly correct output where I'd expect something else.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Here we intentionally allocate only 1 byte,
// even though an `int` takes up 4 bytes
int * address = malloc(1);
address[0] = 16777215; // this value surely takes more than 3 bytes. It cannot fit 1 byte.
address[1] = 1337; // just for demo, let's put a random other number in the next memory cell.
printf("%i\n", address[0]); // Prints 16777215. How?! Didn't we overwrite a part of the number?
return 0;
}
Why does this work? Does malloc actually allocate more than the number of bytes that we pass to it?
EDIT
Thanks for the comments! But I wish to note that being able to write to unassigned memory is not the part that surprises me and it's not part of the question. I know that writing out of bounds is possible and it is "undefined behavior".
For me, the unexpected part is that the line address[1] = 1337; does not in any way corrupt the int value at address[0].
It seems that the explanations for this diverge, too.
#Mini suggests that the reason for this is that malloc actually allocates more than what's passed, because of cross-platform differences.
#P__J__ in the comments says that address[1] for some reason points to the next sizeof(int) byte, not to the next byte. But I don't think I understand what controls this behavior then, because malloc doesn't seem to know about what types we will put into the allocated blocks.
EDIT 2
So thanks to the comments, I believe I understand the program behavior now.
The answer lies in the pointer arithmetic. The program "knows" that an address pointer is of type int, and therefore adding 1 to it (or accessing via address[1]) gives an address of the block that lies 4 (sizeof(int)) bytes ahead.
And if we really wanted, we could move just one byte and really corrupt the value at address[0] by coercing address to char * as described in this answer
Thanks to all and to #P__J__ and #Blastfurnace in particular!
malloc often allocates more than you actually ask for (all system/environment/OS dependent), which is why it works in you scenario (sometimes). However, this is still undefined behavior it can actually allocate only 1 byte (and you are writing to what may not be allocated heap memory).
C doesn't mandate any kinds of bounds checking on array accesses, and it's possible to overflow storage and write into memory you don't technically own. As long as you don't clobber anything "important", your code will appear to work as intended.
However, the behavior on buffer overruns is undefined, so the results will not generally be predictable or repeatable.
This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Is it undefined behaviour to access an array beyond its end, if that area is allocated? [duplicate]
(3 answers)
Array index out of bound behavior
(10 answers)
Getting no segmentation fault when exceeding the size that was allocated for a char * [duplicate]
(1 answer)
Closed 5 years ago.
The title may not be accurate. Please excuse me for being a completely new programmer in c. But it is a genuine question which I believe will benefit others who were as confused by memory and pointers as I was when learning my first low-level programming language, that is C.
Here is what I know in regard to this:
Pointers are variables that store memory addresses.
You can allocate a place in memory using the malloc function from the stdlib.h header file, which returns a pointer to the memory allocated.
The malloc function takes the size of what you want to store in bytes as a parameter
Which leads me to ask: What if you store something of a bigger size in the place in memory allocated by the malloc function, where you passed a smaller size as the parameter for the malloc function?
Naturally, the first thing I did was obviously try it. I take input using scanf, which then stores the input in the allocated memory. Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *string_pointer;
string_pointer = malloc(sizeof(char)*24);
if (string_pointer == NULL){
puts("Memory allocation failed:(");
return 1;
}else{}
scanf("%s",string_pointer);
printf("%s",string_pointer);
return 0;
}
You can see that I allocated a place in memory, passing in sizeof(char)*24 as the parameter. Then I stored the pointer of this memory in the string_pointer variable.
Now if I feed scanf with a string that is more than 24 characters (bigger size than the allocated memory), it still works, When I print out the contents of the memory, I get the whole string as it is, even though that means that it stored a string of a bigger size than what it can hold. This shows that I have an obvious misconception of how memory allocation works. It might be because that malloc doesn't allocate a memory that can only hold the size that I passed to malloc, and the whole size parameter thing is for a totally different purpose.
I am completely confused? How come I just stored a string in a memory allocated that can hold less than the size of the string?
This question already has answers here:
What's the difference between a VLA and dynamic memory allocation via malloc?
(4 answers)
Closed 6 years ago.
In the following code I'm providing size of array at run time.
#include <stdio.h>
int main()
{
int i;
scanf("%d",&i);
int a[i];
}
Please tell me the difference between the code above and code using malloc().
I know that array store is on the stack and dynamic memory (malloc, calloc etc) is on the heap.
So is my code functioning similar to malloc? If not, please explain.
Apart from your code uses VLA which:
did not exist before C99
were introduced as a new feature in C99
are now an optional feature since C11
The difference is that automatic arrays (VLA or static size ones) are automatically release when they go out of scope, so you cannot return them from a function, while dynamically allocated ones persist until they are explicitely freed - which shall happen before you lose a pointer to them if you do not want a memory leak.
The Above statement works in C99, but there are limitations of using this approach:
int a[i] is variable length array not the memory dynamically
allocated, hence it will store on STACK instead of HEAP "which it does
in case of malloc" hence there will be situation when somebody entered
MAX_INT and your STACK memory limit is very less(Ex : Embedded
Systems) then Stack Corruption might occur.
This question already has answers here:
When is malloc necessary in C?
(8 answers)
Closed 8 years ago.
It is often said to use malloc when size is known at run time we could also write
int x;
scanf("%d",&x);
char arr[x];
so why use malloc when we can declare array on the fly.
Writing char arr[x]; will allocate the memory on the stack.
The size of the stack is typically limited to around 1MB. You'll get runtime errors if you exceed this pre-defined amount. Some compilers will allow you to change the stack size, but you'll still hit a limit eventually of many orders of magnitude than you can get with malloc.
VLA [Variable length array] is a concept present in C99 onwards.
malloc() originates much before that.
Also, malloc() and family allocates memory from heap. It does not use the comparatively limited stack space.
OTOH, gcc allocates space for VLAs in the stack itself.
This question already has answers here:
What's the difference between a VLA and dynamic memory allocation via malloc?
(4 answers)
Closed 6 years ago.
There are two ways to allocate memory to an array, of which the size is unknown at the beginning. The most common way is using malloc like this
int * array;
... // when we know the size
array = malloc(size*sizeof(int));
But it's valid too in C99 to define the array after we know the size.
... // when we know the size
int array[size];
Are they absolutely the same?
No they're not absolutely the same. While both let you store the same number and type of objects, keep in mind that:
You can free() a malloced array, but you can't free() a variable length array (although it goes out of scope and ceases to exist once the enclosing block is left). In technical jargon, they have different storage duration: allocated for malloc versus automatic for variable length arrays.
Although C has no concept of a stack, many implementation allocate a variable length array from the stack, while malloc allocates from the heap. This is an issue on stack-limited systems, e.g. many embedded operating systems, where the stack size is on the order of kB, while the heap is much larger.
It is also easier to test for a failed allocation with malloc than with a variable length array.
malloced memory can be changed in size with realloc(), while VLAs can't (more precisely only by executing the block again with a different array dimension--which loses the previous contents).
A hosted C89 implementation only supports malloc().
A hosted C11 implementation may not support variable length arrays (it then must define __STDC_NO_VLA__ as the integer 1 according to C11 6.10.8.3).
Everything else I have missed :-)