Decreasing realloc [duplicate] - c

This question already has answers here:
Using realloc to shrink the allocated memory
(5 answers)
Can I assume that calling realloc with a smaller size will free the remainder? [duplicate]
(5 answers)
what will realloc do to the old pointer [duplicate]
(6 answers)
Closed 2 years ago.
I have a few questions about understanding
realloc behavior.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *str;
/* Initial memory allocation */
str = malloc(5 * sizeof(int));
*str = 1;
*(str + 1) = 2;
*(str + 2) = 3;
*(str + 3) = 4;
*(str + 4) = 5;
/* Reallocating memory */
int i, j;
for (i = 5; i > 0; i--) {
str = realloc(str, i * sizeof(int));
for (j = 0; j < i; j++) {
printf("%d", *(str + j));
}
printf("\n");
}
free(str);
return(0);
}
In this code example, can I be sure that a smaller realloc will drop the highest number?
Is the realloc is only freeing the last memory and keeping the same address in str? Or may the address change even though it's getting smaller and for sure have space in the current place?

Yes. If you have a memory block p of size N and you do realloc(p, M), then (assuming realloc succeeds), the result will contain the first min(N, M) bytes from p.
The address can change, even if the new size is smaller than the old one. realloc simply makes no guarantees about this case (it can even fail).

Related

How does realloc work in C? Does it set to null deallocated memory reference? [duplicate]

This question already has answers here:
Why doesn't my program crash when I write past the end of an array?
(9 answers)
Writing to pointer out of bounds after malloc() not causing error
(7 answers)
Closed 6 days ago.
When I call realloc on a pointer to reduce its size what does it happen?
For example, let's considering this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* a = malloc(4*sizeof(int));
a[0]= 1;
a[1]= 1;
a[2]= 1;
a[3]= 1;
int* temp = realloc(a, 3* sizeof(int));
if(!temp)
exit(1);
a = temp;
a[3] = 10;
return 0;
}
I expect that when I call a = realloc(a, 3* sizeof(int)); it will throw SIGSEGV, but it doesn't.

End of dynamically allocated array [duplicate]

This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 2 years ago.
that's my first question. Sorry if I do something wrong. Thanks for your understanding.
I have a dynamically allocated array,
int *read_array(char *file_path , int *arr){
int max = 0 ,min = 0, i = 0;
FILE *fp = fopen(file_path,"r");
arr= malloc(1 * sizeof(int));
fscanf(fp, "%d,", &arr[i] );
max = arr[i];
min = arr[i];
i++;
arr = realloc(arr , i * sizeof(int));
while(fscanf(fp, "%d,", &arr[i] ) != EOF){
if(max < arr[i]){
max = arr[i];
}
else if(min > arr[i] ){
min = arr[i];
}
i++;
arr = realloc(arr , (i +1) * sizeof(int));
}
printf("%d\n",arr[i + 10]);
free(arr);
}
I tried to print what is at (i+10)th index of my array. It prints "0".
But when I made that printf like printf("%d\n",arr[i + 100000]); I got a seg fault as I expected. But I think I allocated as much memory as "i".
Why arr[i+10] is not giving seg fault ?
Thank you for your time.
This is an array-out-of-bounds logic error, but there's a good chance it's not throwing a segmentation fault because malloc allocated more memory than you were expecting.
The C standard does not require malloc() to return a pointer to exactly the amount of memory you asked for. The parameter you pass to malloc() is treated by the system as the minimum required size for the chunk of memory it returns to you.
It is not uncommon for the system to give you quite a bit more memory than you ask for for alignment and other complicated-operating-system reasons that coders really don't need to know about or understand.
Try compiling and running this program on your system to see proof of what I'm talking about:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define VALUE 150 //Or whatever you want
int main(){
for(int i=0;i<VALUE;++i){
void *pt=malloc((size_t)i);
printf("Asked for %d bytes, received %zd bytes\n",i,malloc_usable_size(pt));
free(pt);
}
}

Free dynamic memory with free() [duplicate]

This question already has an answer here:
free 2d array in c
(1 answer)
Closed 5 years ago.
#include <stdlib.h>
#include <stdio.h>
int main() {
char **last_names;
// last_names has been assigned a char * array of length 4. Each element of the array has
// been assigned a char array of length 20.
//
// All of these memory has been allocated on the heap.
// Free all of the allocated memory (hint: 5 total arrays).
return 0;
}
I know the free() method and this is my approach;
free(*last_names);
free(last_names);
but it's not true. Any help will be appreciated
Guessing from your description of the code, your memory allocation would be:
last_names = malloc(4 * sizeof(char*));
for (int i = 0; i < 4; i++)
last_names[i] = malloc(20 * sizeof(char));
So deallocation should be done as follows:
for (int i = 0; i < 4; i++)
free(last_names[i]);
free(last_names);

C: How to free the initial section of an allocated string?

How can I free a string up to a certain point? For example if I have:
char *s = (char *)malloc(sizeof(char) * 21);
s[20] = '\0';
int i = 0;
while (i < 21)
{
s[i] = i + 'a';
i++;
}
And then I cut off the string at some point and store that half:
*(s + 10) = '\0';
char *m = s + 11;
Is there a way to free s up to s + 10 or the first \0?
Since s has been allocated by the system, you can perform a realloc on it to shorten the size:
s = realloc(s, 11);
But you cannot free the start of an allocated zone without freeing the rest, that you cannot. Use memmove & realloc to shift the data and reduce size afterwards.
Attempting to free a pointer which hasn't been allocated, or an allocated pointer plus an offset results in undefined behaviour.
You could do (as you suggested yourself, but with problems fixed :)):
char *c = strdup(s + 10);
free(s);
s = c;
so now s points to the end of the string.
alternative without strdup but using standard functions only (with the risk of forgetting the null-termination char):
char *c = malloc(strlen(s) - 10 + 1);
strcpy(c,s + 10);
free(s);
s = c;
and the memmove solution I was hinting about at first (avoids to allocate/free but offset/size is trickier to compute):
int offset = 10;
int size = strlen(s) - offset;
memmove(s,s+offset,size);
s[size]='\0'; // null-terminate
s = realloc(s,size+1); // adjust size after null-termination
Is there a way to free s up to s + 10 or the first \0?
No. Not in the standard library at least.
There's realloc but it isn't guaranteed to "free s up to s + 10 or the first \0".

Freeing dynamic 2D array not working as expected in C

When I run code like the following:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int i, count = 0x09;
int sizei = 5, sizej = 2;
int **ary = malloc (sizei * sizeof **ary);
for (i = 0; i < sizei; i++) {
*(ary + i) = malloc (sizej * sizeof *(ary + i));
**(ary + i) = ++count;
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
}
puts("----");
for (i = sizei - 1; i >= 0; i--) {
printf (" %2d |%p| +%x+ \n", i, (ary + i), *(*(ary + i)));
free (*(ary + i));
}
puts("----");
free (ary);
return 0;
}
I would expect that the first half would create a 2d dynamic array of ints called ary (i.e a pointer to a dynamically allocated array of pointers, each pointing to a dynamically allocated array of ints). The 0th element of each array **(ary + i) would then be recursively assigned the current value of count.
The second half would iterate in reverse, freeing each element of ary in the reverse it was malloc'd, followed by freeing ary itself.
This appears to work fine until I try to free *(ary + 0), at which point I get a double free / corruption error. I've included the output.
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
4 |0x1d6f030| +e+
3 |0x1d6f028| +d+
2 |0x1d6f020| +c+
1 |0x1d6f018| +b+
0 |0x1d6f010| +1d6f0b0+
*** Error in `./a.out': double free or corruption (out): 0x0000000001d6f030 ***
I'm curious why the 0th element of the 0th element of ary (i.e *(*(ary + 0) + 0)) or just **ary) became what looks like some memory address (only slighly) out of bounds from what's taken up by this 2d array once it got out of the first loop.
And if I get rid of the second loop and just try to free ary directly without first freeing any of its elements I get something like:
0 |0x1d6f010| +a+
1 |0x1d6f018| +b+
2 |0x1d6f020| +c+
3 |0x1d6f028| +d+
4 |0x1d6f030| +e+
----
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000001d6f010 ***
I don't understand what I've done wrong here. Would using array notation make a difference? I need any solutions to allow me to have a dynamic length of each array independant of the length of the rest of the elements of ary if at all possible. The number elements of ary wouldn't necesarily be known at compile time either. I'm using gcc 4.9 if that's relevant.
Problem 1
int **ary = malloc (sizei * sizeof **ary);
is equivalent to
int **ary = malloc (sizei * sizeof int);
If sizeof a pointer is less than sizeof(int) in your system, you end up accessing memory out of bounds.
You need to use:
int **ary = malloc (sizei * sizeof *ary);
or
int **ary = malloc (sizei * sizeof(int*));
Problem 2
*(ary + i) = malloc (sizej * sizeof *(ary + i));
needs to be
*(ary + i) = malloc (sizej * sizeof **(ary + i));
or
*(ary + i) = malloc (sizej * sizeof int);
or
ary[i] = malloc (sizej * sizeof *ary[i]);
or
ary[i] = malloc (sizej * sizeof int);
ari is pointer a to array of pointer, so size of elements are pointers. In your code, you use sizeof **ary which is an int
int **ary = malloc (sizei * sizeof **ary);
For each of the pointer to array of int elements. In your malloc for those pointers, you use sizeof *(ary+i) which is a pointer to int
*(ary + i) = malloc (sizej * sizeof *(ary + i));
sizeof(int) is not always the same as sizeof(int*). In fact, on most 64 bits systems, which I suspect is what you use, sizeof(int)==4 and sizeof(int*)==8.
My guess is that you are using such a system, and because of that, you do not allocate enough memory for the main ari pointer and you are overflowing it with values, thrashing the content of critical memory management data so future malloc() and free() call have a big chance of failing completely.

Resources