Dynamic char array - c

Trying to allocate a char array of N elements.
#include <stdio.h>
#include <malloc.h>
int main()
{
int N = 2;
char *array = malloc(N * sizeof(char));
array[0] = 'a';
array[1] = 'b';
array[2] = 'c'; // why can i do that??
printf("%c", array[0]);
printf("%c", array[1]);
printf("%c", array[2]); //shouldn't I get a seg fault here??
return 0;
}
The question is:
Since I am allocating 2 * 1 = 2 bytes of memory that means i can have 2 chars in my array. How is it possible that I have more?? I also printed sizeof(*array) and it prints 8 bytes. What am I missing here?

A segmentation fault occurs when a program tries to access a memory address which has not been mapped by the operating system into its virtual memory address space.
Memory allocation occurs in pages (usually 4k or 8k, but you can get larger pages too). So the malloc() call gets a memory page from the OS and carves off a piece of it for the array and returns a pointer to that. In this specific case, there is still a large piece of the page remaining after your array (unallocated but already available for use with subsequent calls to malloc()) - array[2] references a valid address within the page, so no segmentation fault.
However, you are accessing memory beyond the array and as mentioned in the comments, that is undefined behaviour and would probably cause memory corruption in a larger program by overwritting the value of unrelated variables.

The 0th and 1th elements are inside of valid memory allocation. With the 2th element you have trespassed into unallocated memory. Will work fine, until that part of the memory gets allocated for something else, then your 2th element will start having crazy values. Your code will go nuts. But as #jon pointed out, the compiler is supposed to be catching this, unless you have asked it to shutup

Related

Reading into heap memory I shouldn't have access to?

In the example below I have allocated 20 bytes of memory to extend an array by 5 integers. After that I have set the last element to 15 and then reallocated the pointer to 4 bytes (1 integer). Then I print the first 10 elements of the array (it only consists of 6 at this point) and the 9th (which I've previously set to 15) is printed without warnings or errors.
The code :
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[5] = {0};
int *ptr = &arr[0];
ptr = malloc(5 * sizeof(int));
arr[9] = 15;
ptr = realloc(ptr, 1 * sizeof(int));
for (int i = 0; i < 10; ++i)
{
printf("%d\n", arr[i]);
}
free(ptr);
return 0;
}
The result after compiling and running :
0
0
0
0
0
32766
681279744
-1123562100
-1261131712
15
My question is as follows : Why is the 9th element of the array still 15? (why am I able to access it?; Shouldn't the allocated memory be at the first free block of memory my compiler finds and not connected to the array's buffer whatsoever?)
The behaviour of malloc() \ realloc() is irrelevant in this case because in the code in the question the content of arr rather than ptr is modified and displayed, and arr is not dynamically allocated or reallocated. So there is no out-of-bounds access in the dynamic memory. The out-of-bounds access to arr[] has undefined behaviour. You will be stomping on memory not allocated to arr. In some cases that will modify adjacent variables, but in this case you have none, so since stacks most often grow downward, you may be modifying the local variables of the calling function or corrupting the return address of the current function - this being main() even that might not cause any noticeable error. In other cases it will lead to a crash.
However, had you modified ptr[15] and reallocated, then displayed the content at ptr it is most likely that you see a similar result because avoid an unnecessary data move, realloc() reuses the same memory block when the allocation is reduced, and simply reduces its size, returning the remainder to the heap.
Returning memory to the heap, does not change its content or make it inaccessible, and C does not perform any bounds checking, so if you code to access memory that is not part of the allocation it will let you. It simply makes the returned block available for allocation.
Strictly it is undefined behaviour, so other behaviour is possible, but generally C does not generate code to do anything other than the bare minimum required - except possibly in some cases to support debugging.
Your description of what the program is doing is all wrong.
In the example below I have allocated 20 bytes of memory to extend an array by 5 integers
No, you don't. You can't extend arr. It's just impossible.
After that I have set the last element to 15
No - because you didn't extend the array so index 9 does not represent the last element. You simply write outside the array.
Look at these lines:
int *ptr = &arr[0];
ptr = malloc(5 * sizeof(int));
First you make ptr point to the first element in arr but rigth after you you make ptr point to some dynamic allocated memory which have absolutely no relation to arr. In other words - the first line can simply be deleted (and probably the compiler will).
In the rest of your program you never use ptr for anything. In other words - you can simply remove all code using ptr. It has no effect.
So the program could simply be:
int main()
{
int arr[5] = {0};
arr[9] = 15;
for (int i = 0; i < 10; ++i)
{
printf("%d\n", arr[i]);
}
return 0;
}
And it has undefined behavior because you access arr out of bounds.
Why is the 9th element of the array still 15?
The "most likely reality" is that the OS provides a way to allocate area/s of virtual pages (which aren't necessarily real memory and should be considered "pretend/fake memory"), and malloc() carves up the allocated "pretend/fake memory" (and allocates more area/s of virtual pages if/when necessary, and deallocates areas of virtual pages if/when convenient).
Freeing "pretend/fake memory that was carved up by malloc()" probably does no more than alter some meta-data used to manage the heap; and is unlikely to cause "pretend/fake memory" to be deallocated (and is even less likely to effect actual real physical RAM).
Of course all of this depends on the environment the software is compiled for, and it can be completely different; so as far as C is concerned (at the "C abstract machine" level) it's all undefined behavior (that might work like I've described, but may not); and even if it does work like I've described there's no guarantee that something you can't know about (e.g. a different thread buried in a shared library) won't allocate the same "pretend/fake memory that was carved up by malloc()" immediately after you free it and won't overwrite the data you left behind.
why am I able to access it?
This is partly because C isn't a managed (or "safe") language - for performance reasons; typically there are no checks for "array index out of bounds" and no checks for "used after it was freed". Instead, bugs cause undefined behavior (and may be critical security vulnerabilities).
int arr[5] = {0}; // these 5 integers are kept on the stack of the function
int *ptr = &arr[0]; // the pointer ptr is also on the stack and points to the address of arr[0]
ptr = malloc(5 * sizeof(int)); // malloc creates heap of size 5 * sizeof int and returns a ptr which points to it
// the ptr now points to the heap and not to the arr[] any more.
arr[9] = 15; //the array is of length 5 and arr[9] is out of the border of maximum arr[4] !
ptr = realloc(ptr, 1 * sizeof(int)); //does nothing here, since the allocated size is already larger than 1 - but it depends on implementation if the rest of 4 x integer will be free'd.
for (int i = 0; i < 10; ++i) // undefined behavior!
{
printf("%d\n", arr[i]);
}
free(ptr);
return 0;`
In short:
Whatever you do with/to a copy of the address of an array inside a pointer variable, it has no influence on the array.
The address copy creates no relation whatsoever between the array and memory allocated (and referenced by the pointer) by a later malloc.
The allocation will not be right after the array.
A realloc of a pointer with a copy of an array access does not work. Realloc only works with pointers which carry the result of a succesful malloc. (Which is probably why you inserted the malloc.)
Longer:
Here are some important facts on your code, see my comments:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[5] = {0}; /* size 5 ints, nothing will change that */
int *ptr = &arr[0]; /* this value will be ignored in the next line */
ptr = malloc(5 * sizeof(int)); /* overwrite value from previous line */
arr[9] = 15; /* arr still only has size 5 and this access beyond */
ptr = realloc(ptr, 1 * sizeof(int)); /* irrelevant, no influence on arr */
for (int i = 0; i < 10; ++i) /* 10 is larger than 5 ... */
{
printf("%d\n", arr[i]); /* starting with 5, this access beyond several times */
}
free(ptr);
return 0;
}
Now let us discuss your description:
In the example below I have allocated 20 bytes of memory ....
True, in the line ptr = malloc(5 * sizeof(int)); (assuming that an int has 4 bytes; not guaranteed, but let's assume it).
... to extend an array by 5 integers.
No. No attribute of the array is affected by this line. Especially not the size.
Note that with the malloc, the line int *ptr = &arr[0]; is almost completely ignored. Only the part int *ptr; remains relevant. The malloc determines the value in the pointer and there is no relation to the array whatsoever.
After that I have set the last element to 15 ...
No, you access memory beyond the array. The last useable array element is arr[4] noce code until now has changed that. Judgin from the output, which still contains "15", you got "lucky", the value has not killed anything and still is in memory. But it is practically unrelated to the array and is also practically guaranteed outside of the allocated memory referenced by ptr.
... and then reallocated the pointer to 4 bytes (1 integer).
True. But I do not really get the point you try to make.
Then I print the first 10 elements of the array ...
No, you print the first 5 elements of the array, i.e. all of them.
Then you print 3 values which happen to be inside memory which you should not access at all. Afterwards you print a fifth value outside of the array, which you also should not access, but which happens to be still be the 15 you wrote there earlier - and should not have in the first place either.
... (it only consists of 6 at this point) ...
You probabyl mean 5 values from the array and 1 from ptr, but they are unrelated and unlikely to be consecutive.
... and the 9th (which I've previously set to 15) is printed without warnings or errors.
There is no 9th, see above. Concerning the lack of errors, well, you are not always lucky enough to be told by the compiler or the runtime that you make a mistake. Life would be so much easier if they could notify you of reliably all mistakes.
Let us go on with your comments:
But isn't arr[9] part of the defined heap?
No. I am not sure what you mean by "the defined heap", but it is surely neither part of the array nor the allocated memory referenced by the pointer. The chance that the allocation is right after the array is as close to zero as it gets - maybe not precisely 0, but you simply are not allowed to assume that.
I have allocated 20 bytes, ...
On many current machines, but assuming that an int has four bytes is also not a afe assumption. However, yes, lets assume that 5 ints have 20 bytes.
... so arr should now consist of 10 integers, instead of 5.
Again no, whatever you do via ptr, it has no influence on the array and there is practically no chance that the ptr-referenced memory is right after the array by chance. It seems that you assume that copying the address of the array into the pointer has an influence on array. That is not the case. It had once a copy of the arrays address, but even that has been overwritten one line later. And even if it had not been overwritten, reallocing the ptr would make an error (that is why you inserted the malloc line, isn't it?) but still not have any effect on the array or its size.
... But I don't think I am passing the barrier of the defined heap.
Again, lets assume that by "the defined heap" you mean either the array or the allocated memory referenced by ptr. Neither can be assumed to contain the arr[9] you access. So yes, you ARE accessing outside of any memory you are allowed to access.
I shouldn't be able to access arr[9], right?
Yes and no. Yes, you are not allowed to do that (with or without the realloc to 1).
No, you cannot expect to get any helpful error message.
Let's look at your comment to another answer:
My teacher in school told me that using realloc() with a smaller size than the already allocated memory frees it until it becomes n bytes.
Not wrong. It is freed, which means you are not allowed to use it anymore.
It is also theoretically freed so that it could be used by the next malloc. That does however not mean that the next malloc will. In no case implies freeing memory any change to the content of that freed memory. It definitly could change, but you cannot expect it or even rely on it. Tom Kuschels answer to this comment is also right.

How many members calloc allocates in C [duplicate]

This question already has answers here:
No out of bounds error
(7 answers)
Closed 3 years ago.
I am expecting the following snippet to allocate memory for five members using calloc.
$ cat calloc.c
// C program to demonstrate the use of calloc()
// and malloc()
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr;
arr = (int *)calloc(5, sizeof(int));
printf("%x\n", *arr);
printf("%x\n", *(arr+1));
printf("%x\n", *(arr+2));
printf("%x\n", *(arr+3));
printf("%x\n", *(arr+4));
printf("%x\n", *(arr+5));
printf("%x\n", *(arr+6));
// Deallocates memory previously allocated by calloc() function
free(arr);
return(0);
}
But it seems to be allocating more than five; it is allocating six members, why?
./a.out
0
0
0
0
0
0
411
Allocating memory isn't like buying lollipops. Allocating memory is more like buying land.
If you buy five lollipops and you try to eat the sixth one, this obviously doesn't work — it's pretty nonsensical to even talk about "trying to eat the sixth one".
But if you buy a ten foot by fifty foot plot of land, and you start putting up 10x10 foot buildings, and after building five of them (completely occupying your land), you build a sixth one encroaching over onto your neighbor's land, your neighbor might not notice right away, so you might get away with it. (For a little while, anyway. There's bound to be trouble in the end.)
Similarly, if you allocate an array of size 5 and then try to access a nonexistent 6th element, there's no law of nature that prevents it the way there was when you tried to eat the nonexistent 6th lollipop. In C you don't generally get an error message about out-of-bound array access, so you might get code that seems to work, even though it's doing something totally unacceptable, like encroaching on a neighbor's land.
First of all, let's get something clear: for all purposes, *(a+x) is the same as a[x].
C has free memory access. If you do arr[1000], you will still get a value printed, or the program will crash with a segmentation fault. This is the classic case of undefined behaviour. The compiler cannot know whether the code you wrote is wrong or not, so it cannot throw an error. Instead, the C standard says this is undefined behaviour. What this means is that you are accessing memory you shouldn't.
You, as the programmer, are responsible to check that you don't go out of bounds of the array and not the compiler. Also, calloc initializes all elements with 0. Why do you think you got 411? Try running it again, you will probably get a different value. That memory you are accessing at a[5] is not allocated for the array. Instead, you are going out of the bounds of the array. That memory could have very well been allocated to something else. If it was allocated to another program, you would get a segmentation fault when you run the program.
It hasn't allocated memory more than 5. It has allocated 5 members and initialized them with 0. When you access to outside of the allocated memory, it may be written anything into it, and not certainly a non zero value.
Every time a malloc, calloc or realloc is called, the memory allocation is done from heap area.
Run Time/ Dynamic allocation -> Heap
Static/Compile Time-> Stack
// C program to demonstrate the use of calloc()
// and malloc()
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr;
arr = (int *)calloc(5, sizeof(int)); // dynamically allocate memory for 5 element each of size of integer variables and intializes all with 0.
printf("%x\n", *arr);//array name is a constant pointer(points to base address of the array
printf("%x\n", *(arr+1));
printf("%x\n", *(arr+2));
printf("%x\n", *(arr+3));
printf("%x\n", *(arr+4));
printf("%x\n", *(arr+5));
printf("%x\n", *(arr+6));// you are accessing memory which is not the part of your pointer variable. There are chances that this is the part of the some other program or variable.
// Deallocates memory previously allocated by calloc() function
free(arr);
arr=NULL;//always assign pointer to null to avoid any dangling pointer situation
return(0);
}

How much memory does calloc actually allocate?

The following code when tested, gives output as
1
0
0
2
0
which is amazing because ptr[3], ptr[4] did not have any memory allocation. Although they stored value in them and prints it. I tried the same code for few larger i's in ptr[i] which again compiled successfully and gives result but for very large value of i, of the order of 100000,program get crashed. if calloc() allocates such a large memory on single call then it is not worth effective. So how calloc() works? Where is this discrepancy?
#include <stdio.h>
void main() {
int * ptr = (int *)calloc(3,sizeof(int));//allocates memory to 3 integer
int i = 0;
*ptr = 1;
*(ptr+3) = 2;//although memory is not allocated but get initialized
for( i =0 ; i<5 ; ++i){
printf("%d\n",*ptr++);
}
}
After that i tried this code which continuously runs without any output
#include <stdio.h>
void main() {
int * ptr = (int *)calloc(3,sizeof(int));
int i = 0;
*ptr = 1;
*(ptr+3) = 2;
//free(ptr+2);
for( ; ptr!=NULL ;)
{
//printf("%d\n",*ptr++);
i++;
}
printf("%d",i);
}
You are confounding two kinds of memory allocation: the kernel's and libc's.
When you ask malloc or calloc for 5 bytes, it does not turn around and ask the kernel for 5 bytes. That would take forever. Instead, the libc heap system obtains larger blocks of memory from the kernel, and subdivides it.
Therefore, when you ask for a small amount of memory, there is usually plenty of more accessible memory right after it that has not been allocated yet by libc, and you can access it. Of course, accessing it is an instant recipe for bugs.
The only time that referencing off the end will get a SIGnal is if you happen to be at the very end of the region acquired from the kernel.
I recommend that you try running your test case under valgrind for additional insight.
The code that you have has undefined behavior. However, you do not get a crash because malloc and calloc indeed often allocate more memory than you ask.
One way to tell how much memory you've got is to call realloc with increasing size, until the pointer that you get back is different from the original. Although the standard does not guarantee that this trick is going to work, very often it would produce a good result.
Here is how you can run this experiment:
int *ptr = calloc(1,sizeof(int));
// Prevent expansion of the original block
int *block = calloc(1, sizeof(int));
int *tmp;
int k = 1;
do {
tmp = realloc(ptr, k*sizeof(int));
k++;
} while (tmp == ptr);
printf("%d\n", k-1);
This prints 4 on my system and on ideone (demo on ideone). This means that when I requested 4 bytes (i.e. one sizeof(int) from calloc, I got enough space for 16 bytes (i.e. 4*sizeof(int)). This does not mean that I can freely write up to fourints after requesting memory for a singleint`, though: writing past the boundary of the requested memory is still undefined behavior.
calloc is allocating memory for 3 int's in the given snippet. Actually you are accessing unallocated memory. Accessing unallocated memory invokes undefined behavior.
calloc allocates only the amount of memory that you asked, which in your case in for 3 int variables
but it doesnt create a bound on the pointer that it has created (in your case ptr). so you can access the unallocated memory just by incrementing the pointer. thats exactly whats happening in your case..

C Language - Malloc unlimited space?

I'm having difficulty learning C language's malloc and pointer:
What I learned so far:
Pointer is memory address pointer.
malloc() allocate memory locations and returns the memory address.
I'm trying to create a program to test malloc and pointer, here's what I have:
#include<stdio.h>
main()
{
char *x;
x = malloc(sizeof(char) * 5);
strcpy(*x, "123456");
printf("%s",*x); //Prints 123456
}
I'm expecting an error since the size I provided to malloc is 5, where I put 6 characters (123456) to the memory location my pointer points to. What is happening here? Please help me.
Update
Where to learn malloc and pointer? I'm confused by the asterisk thing, like when to use asterisk etc. I will not rest till I learn this thing! Thanks!
You are invoking undefined behaviour because you are writing (or trying to write) beyond the bounds of allocated memory.
Other nitpicks:
Because you are using strcpy(), you are copying 7 bytes, not 6 as you claim in the question.
Your call to strcpy() is flawed - you are passing a char instead of a pointer to char as the first argument.
If your compiler is not complaining, you are not using enough warning options. If you're using GCC, you need at least -Wall in your compiler command line.
You need to include both <stdlib.h> for malloc() and <string.h> for strcpy().
You should also explicitly specify int main() (or, better, int main(void)).
Personally, I'm old school enough that I prefer to see an explicit return(0); at the end of main(), even though C99 follows C++98 and allows you to omit it.
You may be unlucky and get away with invoking undefined behaviour for a while, but a tool like valgrind should point out the error of your ways. In practice, many implementations of malloc() allocate a multiple of 8 bytes (and some a multiple of 16 bytes), and given that you delicately do not step over the 8 byte allocation, you may actually get away with it. But a good debugging malloc() or valgrind will point out that you are doing it wrong.
Note that since you don't free() your allocated space before you return from main(), you (relatively harmlessly in this context) leak it. Note too that if your copied string was longer (say as long as the alphabet), and especially if you tried to free() your allocated memory, or tried to allocate other memory chunks after scribbling beyond the end of the first one, then you are more likely to see your code crash.
Undefined behaviour is unconditionally bad. Anything could happen. No system is required to diagnose it. Avoid it!
If you call malloc you get and adress of a memory region on heap.
If it returns e.g. 1000 you memory would look like:
Adr Value
----------
1000 1
1001 2
1002 3
1003 4
1004 5
1005 6
1006 0
after the call to strcpy(). you wrote 7 chars (2 more than allocated).
x == 1000 (pointer address)
*x == 1 (dereferenced the value x points to)
There are no warnings or error messages from the compiler, since C doesn't have any range-checking.
My three cents:
Use x, as (*x) is the value that is stored at x (which is unknown in your case) - you are writing to unknown memory location. It should be:
strcpy(x, "123456");
Secondly - "123456" is not 6 bytes, it's 7. You forgot about trailing zero-terminator.
Your program with it's current code might work, but not guaranteed.
What I would do:
#include<stdio.h>
main()
{
char str[] = "123456";
char *x;
x = malloc(sizeof(str));
strcpy(x, str);
printf("%s",x); //Prints 123456
free(x);
}
Firstly, there is one problem with your code:
x is a pointer to a memory area where you allocated space for 5 characters.
*x it's the value of the first character.
You should use strcpy(x, "123456");
Secondly, the memory after your 5 bytes allocated, can be valid so you will not receive an error.
#include<stdio.h>
main()
{
char *x;
x = malloc(sizeof(char) * 5);
strcpy(x, "123456");
printf("%s",x); //Prints 123456
}
Use this...it will work
See difference in your & mine program
Now here you are allocating 5 bytes & writing 6 byte so 6th byte will be stored in next consecutive address. This extra byte can be allocated to some one else by memory management so any time that extra byte can be changed by other program because 6th byte is not yours because you haven't malloc'd that.. that's why this is called undefined behaviour.

Memory assignment in C through pointers

I am learning how to use pointers, so i wrote the below program to assign integer values in the interval [1,100] to some random locations in the memory.
When i read those memory locations, printf displays all the values and then gives me a segmentation fault. This seems an odd behavior, because i was hoping to see either all the values OR a seg fault, but not both at the same time.
Can someone please explain why i got to see both?
Thanks. Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
char first = 'f';
char *ptr_first = &first;
int i=1;
for(i=1;i<101;i++)
*(ptr_first+i) = i;
for(i=1;i<101;i++)
printf("%d\n", *(ptr_first+i));
return EXIT_SUCCESS;
}
Not odd at all. You are using your variable first, which is on the stack. What you essentially do is happily overwriting the stack (otherwise known from buffer overflows on the stack) and thus probably destroying any return address and so on.
Since main is called by the libc, the return to libc would cause the crash.
You're accessing memory past beyond that assigned to first. It is just one character, and, through the ptr_first pointer, you're accessing 100 positions past this character to unreserved memory. This may lead to segfaults.
You have to ensure the original variable has enough memory reserved for the pointer accesses. For example:
char first[100];
This will convert first in an array of 100 chars (basically a memory space of 100 bytes that you can access via pointer).
Note also that you're inserting int into the char pointer. This will work, but the value of the int will be truncated. You should be using char as the type of i.
since ptr_first pointer is pointing to a char variable first. Now when you are incrementing ptr_first, so incremented memory address location can be out of process memory address space, thats why kernel is sending segmentation fault to this process.

Resources