Deallocating 2D array in C - c

For whatever reason I am getting the following error when trying to free the 2D array I created:
Error in `./a.out': free(): invalid next size (fast): 0x0000000001759310 *** Aborted (core dumped)
I printed out the contents of the array and they are correct and I am able access all of the elements. However, I am yet to be able to free it. The error occurs when going through the freeing loop, i.e. freeing double *. Would appreciate any help.
Thanks!
Here is the code:
/*allocation*/
double **block_mat = (double **) malloc (sizeof(double *) * num_blocks);
int i;
for (i = 0; i <num_blocks; i++){
block_mat[i] = (double *) malloc (sizeof(double) * s);
}
/*freeing*/
for (i = 0; i < num_blocks; i++){
free(block_mat[i]);
}
free(block_mat);
EDIT:
The error was found! I under-allocated memory...So when I printed out my arrays they looked like everything was fine... I allocated arrays of sizes s, but used s^2 instead. Thank you everyone!

You allocate space for s doubles for each block_mat[i]. Later, you access
block_mat[i][block_index] = 0;
block_index++;
but you never check that block_index goes out of bounds, which it does.
If you write beyond the s allocated doubles, you might corrupt the internal control data for the subsequent pointer, which usually is placed before the pointer returned by malloc and which is required to be intact by free.

Are you sure that these pointers were all allocated with distinct mallocs?
free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);
for (i = 0; i < num_blocks; i++){
free(block_mat[i]);
}
free(block_mat);
If two of them are the same pointer, then you are trying to free something twice.

This is incorrect:
free(my_matrix);
free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
The order should be at least like this:
free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);

You have several problem that can impact allocation. The first, what if the call to strtol fails?
s = (int)strtol(argv [3], &ptr, 10);
You should check the conversion:
#include <errno.h>
...
else {
errno = 0;
long tmp = strtol(argv [3], &ptr, 10);
if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
(errno != 0 && tmp == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (ptr == argv[3]) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
s = (int)tmp;
}
Next, with your allocation and free, you were on the right track, but don't cast the return of malloc. Casting the return only increases the chance of a hard to debug error. When allocating a pointer-to-pointer-to-double, you need to allocate as many pointers as needed. (num_blocks) in your case. When computing the size of the allocation, you can simply dereference the variable being allocated which again lessens the chance of error:
int i;
double **block_mat = malloc (sizeof *block_mat * num_blocks);
/* check allocation for failure */
for (i = 0; i <num_blocks; i++){
block_mat[i] = malloc (sizeof **block_mat * s);
/* check allocation for failure */
}
/*freeing*/
for (i = 0; i < num_blocks; i++){
free (block_mat[i]);
}
free(block_mat);
Note: you must initialize all values in block_mat before you begin referencing the elements to prevent the deference of an unassigned value later. (e.g. double result = block_mat[i][j] * Pi;) Consider adding:
block_mat[i] = malloc (sizeof **block_mat * s);
/* check for failure */
block_mat[i] = 0.0;
Note: When allocating numerical matricies, consider using calloc instead of malloc as it will initialize all values to '0' and prevent the inadvertent dereference of an unassigned valued -- which is undefined behavior. Using calloc you would have:
int i;
double **block_mat = calloc (num_blocks, sizeof *block_mat);
/* check allocation for failure */
for (i = 0; i <num_blocks; i++){
block_mat[i] = calloc (s, sizeof **block_mat);
/* check allocation for failure */
}
/*freeing*/
for (i = 0; i < num_blocks; i++){
free (block_mat[i]);
}
free(block_mat);
Note: when s is greater than 1, you will alloc space for more than one double at each pointer. Noting prevents you from doing that, but you are responsible for handling the offset to each value. (e.g. result = *(block_mat[i] + j + n * sizeof **block_mat) * Pi;, where n is 0 <= n < s) If you are storing multiple doubles in each pointer, consider using a pointer-to-struct instead. E.g.:
typedef struct point {
double x;
double y;
double z;
} point;

Related

Logical error while using realloc() function

I am using dynamic memory allocation in C for a simple problem that I am trying to solve. It involves taking user input for the elements of 2 arrays. I was thinking that I will initialise the array to a large size and use realloc to reduce the size once the input has been completed. ?below is the code for same:
void arrayop()
{
int val, i=0;
int *arr1 = (int*) calloc(100,sizeof(int));
int *arr2 = (int*) calloc(100,sizeof(int));
printf("Enter first array:(-1 to stop)\n");
while(val!=-1)
{
if(val != -1)
{
scanf("%d",&val);
*(arr1 + i) = val;
i++;
}
}
//printf("\t%d\n",i);
arr1 = (int*)realloc(arr1,(i));
//printf("\t%d\n",(sizeof(arr1)));
for(int j=0;j<i;j++)
{
printf("%d ",*(arr1 + j));
}
printf("\n");
}
However, realloc() is somehow overwriting already entered elements and filling them with garbage value. Can anyone give me any insight as to why this is happening, or where I am wrong?
realloc expects the allocation size, but you're telling it how many ints you want. When you call it like this:
arr1 = (int*)realloc(arr1,(i));
i holds the number of ints that you want to allocate space for, but the actual size needed for the allocation is i * sizeof(int), so to fix it you need:
arr1 = realloc(arr1, sizeof(int) * i);
Or, even better:
arr1 = realloc(arr1, sizeof(*arr1) * i);
The second variant will work even if you change the type of arr1 from int * to, say, short *.
You may also want to check the pointer returned by realloc and make sure the allocation succeeded. Note that if realloc fails, arr1 won't be freed and you'll end up leaking it. A better approach is:
int *temp = realloc(arr1, sizeof(*arr1) * i);
if (temp == NULL)
{
fprintf(stderr, "realloc failed\n");
free(arr1);
return;
}
arr1 = temp;
While we're at it, don't cast the result of malloc, calloc, or realloc. See Do I cast the result of malloc?
.

c Segmentation fault in macOS ; sometimes, and sometimes not

void makeDouble(int **a, int *size){
int i, j;
*size *= 2;
*a = (int *)realloc(*a, (*size)*sizeof(int));
for(i=0; i<*size/2; i++){
(*a)[*size/2+i] = (*a)[i] * 2;
}
int temp;
for(i=0; i<*size-1; i++){
for(j=0; j<*size-i-1; j++){
if((*a)[j]>(*a)[j+1]){
temp = (*a)[j];
(*a)[j] = (*a)[j+1];
(*a)[j+1] = temp;
}
}
}
}
$
this is my code. What I wanted to do is getting a size and input as size, then making them all doubled, and sorting them.
But when I compile this, sometimes it collapses with segmentation fault and sometimes doesn't. And sometimes, it says "malloc: * error for object 0x7fda70c02730: incorrect checksum for freed object - object was probably modified after being freed.
* set a breakpoint in malloc_error_break to debug
Abort trap: 6"
Why and What can I do with this? Sorry if my question is bad, I'm beginner with c.
First Segfault
One place where this would cause a segfault for sure is:
int size;
scanf("%d", &size);
int* a = (int *)malloc(size*sizeof(int));
if you pass it a character instead of a number that fits into an integer this would fail, because scanf is not gonna write to size.
You have to check the return of scanf which is the number of input items successfully matched:
if (scanf("%d", &size) != 1) {
fprintf(stderr, "Supplied size is not a valid number.\n");
return 1;
}
Memory Leak
if realloc returns NULL because it failed to allocate enough space, you get a memory leak because you do:
int *a = realloc(a, ...);
This pattern is buggy, because assigning the return of realloc to the array you wanna reallocate means you lose the reference to the allocated array since a == NULL. Do:
int *temp = realloc(a, ...);
if (temp == NULL) {
free(a); // Or continue using it ..
} else {
a = temp;
}
Heap Corruption
Your function makeDouble is causing a heap corruption because you're accessing and modifying out of bound memory. I'm getting a realloc() abort: invalid next size with glibc, so you're most likely smashing the heap already allocated by the runtime, but not reaching the next page, hence no Segfault and a runtime error instead.

how to keep using malloc?

I have a file which stored a sequence of integers. The number of total integers is unknown, so I keep using malloc() to apply new memory if i read an integer from the file.
I don't know if i could keep asking for memory and add them at the end of the array. The Xcode keeps warning me that 'EXC_BAD_EXCESS' in the line of malloc().
How could i do this if i keep reading integers from a file?
int main()
{
//1.read from file
int *a = NULL;
int size=0;
//char ch;
FILE *in;
//open file
if ( (in=fopen("/Users/NUO/Desktop/in.text","r")) == NULL){
printf("cannot open input file\n");
exit(0); //if file open fail, stop the program
}
while( ! feof(in) ){
a = (int *)malloc(sizeof(int));
fscanf(in,"%d", &a[size] );;
printf("a[i]=%d\n",a[size]);
size++;
}
fclose(in);
return 0;
}
Calling malloc() repeatedly like that doesn't do what you think it does. Each time malloc(sizeof(int)) is called, it allocates a separate, new block of memory that's only large enough for one integer. Writing to a[size] ends up writing off the end of that array for every value past the first one.
What you want here is the realloc() function, e.g.
a = realloc(a, sizeof(int) * (size + 1));
if (a == NULL) { ... handle error ... }
Reworking your code such that size is actually the size of the array, rather than its last index, would help simplify this code, but that's neither here nor there.
Instead of using malloc, use realloc.
Don't use feof(in) in a while loop. See why.
int number;
while( fscanf(in, "%d", &number) == 1 ){
a = realloc(a, sizeof(int)*(size+1));
if ( a == NULL )
{
// Problem.
exit(0);
}
a[size] = number;
printf("a[i]=%d\n", a[size]);
size++;
}
Your malloc() is overwriting your previous storage with just enough space for a single integer!
a = (int *)malloc(sizeof(int));
^^^ assignment overwrites what you have stored!
Instead, realloc() the array:
a = realloc(a, sizeof(int)*(size+1));
You haven't allocated an array of integers, you've allocated one integer here. So you'll need to allocate a default array size, then resize if you're about to over run. This will resize it by 2 each time it is full. Might not be in your best interest to resize it this way, but you could also reallocate each for each additional field.
size_t size = 0;
size_t current_size = 2;
a = (int *)malloc(sizeof(int) * current_size);
if(!a)
handle_error();
while( ! feof(in) ){
if(size >= current_size) {
current_size *= 2;
a = (int *)realloc(a, sizeof(int) * current_size);
if(!a)
handle_error();
}
fscanf(in,"%d", &a[size] );;
printf("a[i]=%d\n",a[size]);
size++;
}
The usual approach is to allocate some amount of space at first (large enough to cover most of your cases), then double it as necessary, using the realloc function.
An example:
#define INITIAL_ALLOCATED 32 // or enough to cover most cases
...
size_t allocated = INITIAL_ALLOCATED;
size_t size = 0;
...
int *a = malloc( sizeof *a * allocated );
if ( !a )
// panic
int val;
while ( fscanf( in, "%d", &val ) == 1 )
{
if ( size == allocated )
{
int *tmp = realloc( a, sizeof *a * allocated * 2 ); // double the size of the buffer
if ( tmp )
{
a = tmp;
allocated *= 2;
}
else
{
// realloc failed - you can treat this as a fatal error, or you
// can give the user a choice to continue with the data that's
// been read so far.
}
a[size++] = val;
}
}
We start by allocating 32 elements to a. Then we read a value from the file. If we're not at the end of the array (size is not equal to allocated), we add that value to the end of the array. If we are at the end of the array, we then double the size of it using realloc. If the realloc call succeeds, we update the allocated variable to keep track of the new size and add the value to the array. We keep going until we reach the end of the input file.
Doubling the size of the array each time we reach the limit reduces the total number of realloc calls, which can save performance if you're loading a lot of values.
Note that I assigned the result of realloc to a different variable tmp. realloc will return NULL if it cannot extend the array for any reason. If we assign that NULL value to a, we lose our reference to the memory that was allocated before, causing a memory leak.
Note also that we check the result of fscanf instead of calling feof, since feof won't return true until after we've already tried to read past the end of the file.

Using realloc on a 2D array c

I'm kinda new to C sorry if my questions is somewhat vague;
I need to use realloc on a 2D array without losing it's previous data, I have this function in my program to do it:
void modifyMatrix(int **iMat, int iRow, int iRow2, int iCol)
{
int i;
iMat = (int**)realloc(iMat, (iRow2)*sizeof(int*));
for(i=iRow; i<iRow2; i++)
{
iMat[i]=NULL;
}
for(i=0; i<iRow2; i++)
{
iMat[i]=(int*)realloc(iMat[i], (iCol)*sizeof(int));
}
}
Where iRow is the original size and iRow 2 & iCol are the new size and are all being captured elsewhere in the program.
Whenever I try to print the matrix I keep getting junk data or memory values on the rows and columns that are added, what am I doing wrong?
Let me know if you need the full code or any other questions to clarify, thanks in advance!
Edit:
Below you can see the code I use to create the Matrix
My bad, I think I should've added that the Matrix is already created elsewhere in the program, with this function I'm just trying to modify the dimensions, thanks for the quick response btw!, below you can find the function with which I'm creating the array
void createMatrix(int ***iMat, int iRow, int iCol)
{
int **iRow2 = (int**)calloc(iRow, sizeof(int*));
int i;
for (i=0; i<iRow; i++)
{
iRow2[i] = (int*)calloc(iCol, sizeof(int));
}
*iMat=iRow2;
}
Also, I can only use the array I've already created to do this, I can't create an temp one (which I know would be the easy way to do it)
In c the variables are passed by value, because of this the iMat inside the modifyMatrix() is not modifying the one in the caller function.
You need to pass the address of iMat instead
void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **safe;
safe = realloc(*iMat, iRow2 * sizeof(int *));
if (safe == NULL)
return;
*iMat = safe;
for (i = 0 ; i < iRow ; i++)
{
int *keep_old_pointer;
keep_old_pointer = realloc(safe[i], iCol * sizeof(int));
if (keep_old_pointer == NULL)
do_something_allocation_failed();
safe[i] = keep_old_pointer;
}
for (int i = iRow ; i < iRow2 ; ++i)
safe[i] = malloc(iCol * sizeof(int));
}
Also, don't assign NULL to every element and then try to realloc() because if realloc() makes sense in this situation then you are overwriting the pointers with NULL without freeing them.
And don't overwrite the realloc()ed pointer before checking if the allocation was succesfull, because if it fails you wont be able to free the previous pointer because you would have lost reference to it, causing a memory leak.
When you are passing an array of pointers to a function to realloc, you basically have 2 choices; (1) pass the address of the array to the function (i.e. &array) as the parameter, meaning your function definition will be reallocfoo (int ***array, size_t* size) or (2) assign the return of the function in the calling routine. (e.g. array = reallocfoo (array, &size);)
Since you have already been given answers for (1), let's look at how you would implement and use (2). Note: there is no need to make your function the type of the array, it is just returning a memory address, so making use of a generic void pointer is fine. For example:
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
Also note since you are reallocating an array of pointers, there is no need to pass the type size (a pointer is a pointer is a pointer -- in all the cases we care about here). Putting this to work, since you are not passing the address of your array, you will need to assign the return to complete the reallocation. (much as you did in your code above) e.g.:
if (ridx == rmax) /* if realloc is needed */
ia = xrealloc2 ((void **)ia, &rmax);
Note: the current number of pointers (rmax) is passed as a pointer so its value can be updated to twice current in the reallocation function. (so when you run out next time, you can realloc based on the correct updated current number). Putting all the pieces together, you get a short example that just forces reallocation twice. Additionally, the original allocation is placed in a function as well to keep the main body of code tidy and the return checks for the allocation in the function. (you can decide how you handle memory exhaustion -- NULL return or exit, examples of both are shown in the two functions)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define RMAX 2
#define COLS 5
void *xcalloc (size_t n, size_t s);
void *xrealloc2 (void **memptr, size_t *n);
int main (void) {
int **ia = NULL;
size_t rmax = RMAX;
size_t rows = 0;
size_t ridx = 0, cidx = 0;
srand (2275311); /* arbitrary repeatable seed */
ia = xcalloc (RMAX, sizeof *ia);
/* intentionally force reallocation */
while (ridx < 3 * RMAX) {
ia[ridx] = xcalloc (COLS, sizeof **ia);
for (cidx = 0; cidx < COLS; cidx++)
ia[ridx][cidx] = rand () % 1000 + 1;
ridx++;
if (ridx == rmax)
ia = xrealloc2 ((void **)ia, &rmax);
}
rows = ridx;
printf ("\n the reallocated 2D array elements are:\n\n");
for (ridx = 0; ridx < rows; ridx++) {
for (cidx = 0; cidx < COLS; cidx++)
printf (" %4d", ia[ridx][cidx]);
putchar ('\n');
}
putchar ('\n');
for (ridx = 0; ridx < rows; ridx++)
free (ia[ridx]);
free (ia);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
/* realloc array of pointers ('memptr') to twice current
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer
* to the current number so that its updated value is preserved.
* no pointer size is required as it is known (simply the size
* of a pointer
*/
void *xrealloc2 (void **memptr, size_t *n)
{
void *tmp = realloc (memptr, *n * 2 * sizeof tmp);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
return NULL;
}
memptr = tmp;
memset (memptr + *n, 0, *n * sizeof tmp);
*n *= 2;
return memptr;
}
After you compile the code and run it, it will confirm that instead of just the maximum 2 rows (pointers) originally allocated, reallocation occurs twice increasing that number to 8 (e.g. 2->4->8) so all 6 rows of integers assigned are properly allocated:
the reallocated 2D array elements are:
155 573 760 410 956
553 271 624 625 934
259 291 811 161 185
756 211 16 6 449
124 869 353 210 317
310 181 897 866 831
If you have any questions, let me know. Don't forget, always run any code that allocates or reallocated through valgrind (or similar memory checker) to insure your memory use is correct and that your free all memory you allocate.
==29608== Memcheck, a memory error detector
==29608== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29608== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==29608== Command: ./bin/realloc2d
==29608==
the reallocated 2D array elements are:
<snip>
==29608==
==29608== HEAP SUMMARY:
==29608== in use at exit: 0 bytes in 0 blocks
==29608== total heap usage: 9 allocs, 9 frees, 232 bytes allocated
==29608==
==29608== All heap blocks were freed -- no leaks are possible
==29608==
==29608== For counts of detected and suppressed errors, rerun with: -v
==29608== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
You can compile the code above with the -DDEBUG flag to have it print to stdout each time it reallocates and provide the current count of pointers allocated. Good luck.
On success, realloc frees the pointer you pass to it and returns a pointer to the newly allocated memory. You're getting "junk values" because dereferencing a pointer to freed memory is undefined behavior.
It's not pretty, but the way to fix this (as another answer pointed out) is to pass a triple pointer (int***). That way the function can modify the original value of the pointer. This is how you simulate reference semantics in C, which is a strictly "pass by value" language.
void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol)
{
int i;
int **newMatrix = realloc(*iMat, iRow2 * sizeof(int*));
if (newMatrix == NULL) {
/* handle realloc error here */
}
else {
*iMat = newMatrix; /* assign pointer to the new memory */
}
for(i=iRow; i<iRow2; i++)
{
(*iMat)[i]=NULL;
}
for(i = 0; i < iRow2; i++)
{
int* newRow = realloc((*iMat)[i], (iCol)*sizeof(int));
if (newRow == NULL) {
/* handle realloc error here */
}
else {
(*iMat)[i] = newRow;
}
}
}
You've also got to add some error checking. If realloc fails and returns a NULL pointer, you've just created a memory leak: you no longer have the previous value of the pointer.
Note that I removed all of your casts. It's bad practice to cast the return of malloc and friends in C.

Find a memory leak in C

I'm trying to find a memory leak in the folowing code. valgrind gives me this:
==14160== 1,850 (592 direct, 1,258 indirect) bytes in 9 blocks are definitely lost in loss record 2 of 5
==14160== at 0x4904A06: malloc (vg_replace_malloc.c:149)
==14160== by 0x405B1F: tsCreate (ticket_set.c:55)
==14160== by 0x401ECA: test1TS (main.c:62)
==14160== by 0x40557C: main (main.c:424)
and here's the function:
TicketSetStatus tsCreate(TicketSet* t, int n, int c) {
if(t==NULL){
return TS_CANNOT_CREATE;
}
if (n <= 0){
return TS_ILLEGAL_PARAMETER;
}
t->usedTravels = 0;
t->originalTravels = n;
t->cost = c;
t->moneyLeft = n * c;
//Date time is array of travels:
t->dates = malloc(sizeof(DateTime *)* (n)); //todo maybe c99 allows dynamic arrays?
for (int i = 0; i < n; i++) {
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1);
if (t->dates[i] == NULL) {
free( t->dates);
return TS_CANNOT_CREATE;
}
}
return TS_SUCCESS;
}
TicketSetStatus tsDestroy(TicketSet* t, int* moneyLeft) {
if (t == NULL) {
return TS_FAIL;
}
*moneyLeft = (t->cost) * (t->originalTravels-t->usedTravels);
for (int i = 0; i < t->originalTravels; i++){
free(t->dates[i]);
}
free(t->dates);
t=NULL;
return TS_SUCCESS;
}
when the struct is:
struct TS_element {
int usedTravels;
int originalTravels;
int cost;
DateTime* dates;
int moneyLeft;
};
and
typedef char* DateType
actually playing with free crashes the program more often than not so i'm inclined to live with the memory leak as long as the program functions correctly.
How are you using this array of DateTime? If you are stomping on the values later you will get leaks. Perhaps a confusion about string assignment? ie
char someDateValue[] = "2012-08-15";
t->dates[0] = someDateValue; // Leak -- your allocated string is lost
Instead:
strcpy( t->dates[0], someDateValue );
There is a definite leak in your error condition in tsCreate:
for (int i = 0; i < n; i++) {
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1);
if (t->dates[i] == NULL) {
free(t->dates); // Leak -- every element up to i-1 is lost
return TS_CANNOT_CREATE;
}
}
Are you calling tsDestroy after you've finished with data initialised by tsCreate? Perhaps you're returning from main without cleaning up.
If none of this helps, you should post additional code to show how you are using your data structure.
For at least one error you can focus solely on
...
t->dates = malloc(sizeof(DateTime*) * (n)); /* first malloc */
for (int i = 0; i < n; i++) { /* call this loop 1 */
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1); /* second malloc */
if (t->dates[i] == NULL) { /* test for malloc error */
free( t->dates); /* free the base array/list */
return TS_CANNOT_CREATE; /* exit function */
}
}
...
The problem is if the second malloc fails, the free only frees the base (first) malloc. It does not free any other memory allocations created by the second malloc
in loop 1, on a previous loop 1 iteration. I.e. if t->dates[i] = malloc(... fails when i is equal to 5 then the memory blocks allocated in the iterations 0 to 4 are not freed before exiting the function.
Hopefully that makes sense.
Update #paddy is correct in noting the error of t->dates[0] = someDateValue
which in this case what that is saying is:
char someDateValue[] = "2012-08-15";
could also be written in this case as
char *someDateValue = "2012-08-15";
so that
t->dates[0] = someDateValue;
simply assigns the pointer of the string, replacing the pointer to the freshly allocated block in the preceding malloc.
Ref: If you are still confused you can read the C FAQ question 6.3 So what is meant by the ``equivalence of pointers and arrays'' in C? as well as the rest of the C FAQ.
And is correct to suggest str[n]cpy (or similar replacements) to copy the array contents (rather than its pointer) to the freshly allocated memory block.

Resources