I am learning the basics of C, and now working with malloc(). Say I have a function that asks the user for input, populates a structure with said data, and that structure in saved in an array (all passed by reference from a main function).
I ran the program through Valgrind, I get the "still reachable" bytes (which should be ok right? not considered a leak), but any data saved I get lost blocks.
How would I go freeing that memory after the program has finished running? Also I have some (2) questions within the code just to clarify some things and would appreciate if someone could explain them to me.
Here is some code similar to what I am trying to do:
I have the following struct declared:
struct Person {
char name[MAX_INPUT];
int age;
};
I am writing a function that goes like this:
int function2(struct Person *list, int *index) {
struct Person *prsn = malloc(sizeof(struct Person));
// !Why do we sometimes cast the malloc or not?
// I sometimes get errors when I do, sometimes when I don't,
// while the surrounding code is pretty much the same.
assert(prsn != NULL);
// User input code goes here ...
// Now to save the Person created
strcpy(prsn->name, nameInput);
prsn->age = ageInput;
list[(*index)++] = *prsn;
// !Why use the dereferencing *prsn here?
// why not directly prsn? Or is that saving the memory address and not very useful.
return 0;
}
And this is my main function:
int main(int argc, char *argv[]) {
struct Person personList[MAX_SIZE];
int index;
function2(personList, &index);
// Before closing, I want to free any mallocs I have done here. free()
return 0;
}
Valgrind report:
LEAK SUMMARY:
==1766== definitely lost: 44 bytes in 1 blocks
==1766== indirectly lost: 0 bytes in 0 blocks
==1766== possibly lost: 0 bytes in 0 blocks
==1766== still reachable: 10,355 bytes in 34 blocks
==1766== suppressed: 0 bytes in 0 blocks
Thank you in advance.
Edit: Fixed function2 parameters, return and other things. I apologize, was writing it quickly to illustrate my main question about freeing memory. Thanks for the corrections tips, but the real code is actually compiling correctly and everything.
Edit2: After adding a simple loop at the end of main like suggested to use free(), I get the following errors.
==2216== LEAK SUMMARY:
==2216== definitely lost: 44 bytes in 1 blocks
==2216== indirectly lost: 0 bytes in 0 blocks
==2216== possibly lost: 0 bytes in 0 blocks
==2216== still reachable: 10,355 bytes in 34 blocks
==2216== suppressed: 0 bytes in 0 blocks
==2216==
==2216== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==2216==
==2216== 1 errors in context 1 of 2:
==2216== Invalid free() / delete / delete[] / realloc()
==2216== at 0x563A: free (in /usr/local/Cellar/valgrind/3.8.1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==2216== by 0x10000194E: main (in ./test.out)
==2216== Address 0x7fff5fbf9dd0 is on thread 1's stack
==2216==
==2216== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Code Analysis
Let's dissect this a bit at a time:
int function2(struct Person *list) {
As Iserni noted in his answer, this definition is inconsistent with your call to the function. I agree in general with his correction for the existing code (but I'm going to recommend modifying it shortly):
int function2(struct Person *list, int *index)
struct Person *prsn = malloc(sizeof(struct Person));
// !Why do we sometimes cast the malloc or not?
// I sometimes get errors when I do, sometimes when I don't,
// while the surrounding code is pretty much the same.
It depends on whether you're in C or C++; in C++, you must cast the return value from malloc() (if you use malloc() at all; you usually shouldn't in C++). In C, the cast is optional. There is a school of thought that omitting the cast reveals errors that inserting the cast can hide. I don't subscribe to that; I believe that malloc() should have been declared via <stdlib.h> and the compiler should be warning if there is no declaration in scope, and if there's a declaration in scope, the cast can't cover up sins. The other possible problem is that you assign a pointer to a non-pointer; that would be a mistake that the compiler should be complaining about too.
assert(prsn != NULL);
This is not normally considered a sensible long-term method of handling memory allocation errors.
// User input code goes here ...
// Now to save the Person created
strcpy(prsn->name, nameInput);
prsn->age = ageInput;
list[(*index)++] = *prsn;
// !Why use the dereferencing *prsn here?
Because:
list is a struct Person *.
Therefore list[i] is a struct Person (albeit you spelled i as (*index)++).
Therefore you must assign a struct Person to it.
prsn is a struct Person *.
Therefore *prsn is also a struct Person.
Therefore the assignment is 'correct'.
It also gives you the leak.
You've overwritten the content of list[i] with the content of *prsn.
You've not save the pointer to prsn anywhere.
So you leak memory as you return from the function.
The surgery required to fix this is non-negligible:
int function2(struct Person **item)
...
*item = prsn;
and you have to revise the call; I'll come back to that when dissecting main().
// why not directly prsn? Or is that saving the memory address and not very useful.
}
Your function is declared to return an int but you show no return. If you aren't going to return a value, declare the function as void, especially if you're going to ignore the return value as your code in main() does.
Your last comment is mostly covered by the discussion above; saving the memory address is crucial to stopping the leak so it is very useful.
And this is my main function:
int main(int argc, char *argv[]) {
struct Person personList[MAX_SIZE];
int index;
Using an uninitialized variable is bad news. It is at best only accidentally zeroed. You can't afford to have random values in use as array indexes; initialize it explicitly. Also, we're going to need an array of pointers, not an array of structures:
struct Person *personList[MAX_SIZE];
int index = 0;
...other code...
function2(personList, &index);
With the revised function:
function2(&personList[index++]);
This is preferable; it means that function2() doesn't need to know about the array; you just pass it the address of the pointer to which the allocated memory pointer should be assigned. This reduces the coupling between your main() function and function2(), which makes the code simpler all around.
// Before closing, I want to free any mallocs I have done here. free()
So you write:
for (int i = 0; i < index; i++)
free(personList[i]);
This releases all the memory allocated.
return 0;
}
I like to see an explicit return at the end of main(), even though C99 says it isn't 100% necessary.
Make sure you are compiling with enough warnings enabled. If you're using GCC, then gcc -Wall should be the minimum level of compilation warning you run with (and you should have no warnings in your code when you do so). I run with more stringent warnings: gcc -std=c99 -Wall -Wextra -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes -Wshadow usually. You need to include -O3 (or some level of optimization) to get some warnings. The stuff about prototypes reflects paranoia about an old code-base I work with which still has K&R function definitions around.
Answering comments
First question while I go over your details and try things out: is there a memory impact between an array of structs and an array of pointers?
Yes, but it may not be what you're thinking of. If you use an array of structures, there's no need to allocate memory dynamic for the structures since the compiler's already allocated them for you. Since the purpose of the exercise is to use pointers and malloc(), it is better, therefore, to use pointers. In terms of space, there will be slightly more total memory used with the array of pointers (but there will be less memory leaked).
I am trying to change my code to use an array of pointers. But using function2(personList, &index); to call function2 now gives me the following warning: incompatible pointer types passing 'struct Person *[512]' to parameter of type 'struct Person *'. Is it OK if I write extra code in my main question to go into details? As a note, I'm trying to reference variables as much as possible, so as to not temporarily have the program copy data from function to function.
The compiler is correct if you've not made all the changes. Your code using two arguments copies more data between functions than my code using one argument.
Version 1
The following program uses the proposed single-argument function2() to reduce the coupling between the main() function and function2(), simplifying both.
This code compiles with no warnings under GCC 4.7.1 on Mac OS X 10.7.5 using the command line:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition mem.c -o mem
When run under valgrind, it comes up with no memory leaked.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_INPUT = 28 };
enum { MAX_SIZE = 3 };
struct Person
{
char name[MAX_INPUT];
int age;
};
static void function2(struct Person **list)
{
struct Person *prsn = malloc(sizeof(struct Person));
assert(prsn != NULL);
char *nameInput = "This is my name";
int ageInput = 29; // Again!
strcpy(prsn->name, nameInput);
prsn->age = ageInput;
*list = prsn;
}
int main(void)
{
struct Person *personList[MAX_SIZE];
int index = 0;
function2(&personList[index++]);
function2(&personList[index++]);
function2(&personList[index++]);
for (int i = 0; i < index; i++)
free(personList[i]);
return 0;
}
Version 2
This keeps the two-argument version of function2() and has it do the counting that main() should be doing on its own. This program also compiles cleanly and runs cleanly under valgrind.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_INPUT = 28 };
enum { MAX_SIZE = 3 };
struct Person
{
char name[MAX_INPUT];
int age;
};
static void function2(struct Person **list, int *index)
{
struct Person *prsn = malloc(sizeof(struct Person));
assert(prsn != NULL);
char *nameInput = "This is my name";
int ageInput = 29; // Again!
strcpy(prsn->name, nameInput);
prsn->age = ageInput;
list[(*index)++] = prsn;
}
int main(void)
{
struct Person *personList[MAX_SIZE];
int index = 0;
function2(personList, &index);
function2(personList, &index);
function2(personList, &index);
for (int i = 0; i < index; i++)
free(personList[i]);
return 0;
}
I assume that your function2 is really
int function2(struct Person *list, int *index)
You would save your malloc'ed pointer there with
list[(*index)++] = prsn;
Then in main you would free the list with
while(index)
free(list[--index]);
In object oriented programming languages, an array of objects is really just an array of pointers to the objects. So if a pointer takes 4 bytes, and an object takes 5, an array of 10 objects will actually be 4*10 bytes long (plus overhead).
MyClass[] my_variable = new MyClass[10]; // this will allocate 10*pointersize bytes, plus overhead, you still need to allocate more space for the objects themselves
In C, an array of structures is an array of structures. If a structure takes 8 bytes, an array of 10 of them takes 80 bytes. You don't need to allocate even more space. It's already there.
struct data_t my_variable[10]; // this will allocate 10*sizeof(data_t) bytes
So the easy answer is:
int function2(struct Person *list, int *index) {
char* nameInput;
// User input code goes here ...
// IMPORTANT: the user input code must allocate the space for nameInput
// if it doesn't, then a copy of the buffer must be made
// instead of the direct assignment below
// the memory for this instance of the person was already created when the
// array was created, so just save the values
list[*index].name = nameInput;
list[*index].age = ageInput;
*index += 1;
return 0;
}
When your code executes this line:
list[(*index)++] = *prsn;
It is quite literally copying 8 bytes (on a 32 bit machine, sizeof(int) + sizeof(char*)), as I think you noticed something was up with your commment "// !Why use the dereferencing *prsn here?"
The address to the memory allocated with malloc isn't being copied in that line, but the contents of the memory are. That's why it is a memory leak, the address is lost when the function exits because it was never put into the array.
Related
I am trying to save information from a file to structs in the heap.
The problem is: if i print out the information in the for loop where i save the data, it works well, but when i print out the data outside that for loop i get only garbage
i wanna know why :( probably i am doing a bad work with the malloc
i could work inside the first for loop but i want to know what i am doing wrong
typedef struct{
int tipoDeCodificacion;
void* carta;
}pedido;
typedef struct{
void* nombre;
void* regalo;
}regalos;
void creacionRegalos(FILE *cartas){
FILE *final=fopen("regalos.txt","w");
int cantidadCartas, i;
fscanf(cartas,"%d\n",&cantidadCartas);
printf("%d\n",cantidadCartas);
pedido *Pedidos=(pedido *)malloc(sizeof(cantidadCartas));
regalos **Regalos=malloc(sizeof(regalos *)*cantidadCartas);
for(i=0;i<cantidadCartas;i++){
char *lineaCodificada=malloc(sizeof(char)*100);
int *tipo=malloc(sizeof(int));
fscanf(cartas,"%d\n",tipo);
Pedidos[i].tipoDeCodificacion=*tipo;
printf("%d\n",Pedidos[i].tipoDeCodificacion); //this print works well
fgets(lineaCodificada,100,cartas);
Pedidos[i].carta=lineaCodificada;
puts(Pedidos[i].carta); //this print works well
}
for (i = 0; i < cantidadCartas; i++) {
printf("%d\n",Pedidos[i].tipoDeCodificacion); //just prints garbage
printf("%s\n",(char *)Pedidos[i].carta);//prints garbage
}
}
The line:
pedido *Pedidos=(pedido *)malloc(sizeof(cantidadCartas));
is invalid. You are allocating memory for sizeof(int) bytes. You should:
pedido *Pedidos=(pedido *)malloc(sizeof(*Pedidos) * cantidadCartas);
allocate memory for contidadCartas count of pedido structures. The time you access Pedidos memory using pedido* pointer you do undefined behavior.
Your code is really hard to read, badly indented, with strange locale names, no error checking and it leaks memory for all malloc you call. A good code would check all error places if (Pedidos == NULL) { handle_error(); } and if(fscanf("%d", ....) != 1) etc. The allocation of int *typo = malloc(sizeof(int)); straight up leaks memory - it is nowhere freed. I also strongly encourage you to write all code, including all structure, variables and function names in english.
I've been inspecting the heap memory when executing the following code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct data {
char name[64];
};
struct fp {
int (*fp)();
};
void winner()
{
printf("level passed\n");
}
void nowinner()
{
printf("level has not been passed\n");
}
int main(int argc, char **argv)
{
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = nowinner;
printf("data is at %p, fp is at %p\n", d, f);
strcpy(d->name, argv[1]);
f->fp();
}
The code is compiled like this:
gcc winner.c -w -g -fno-stack-protector -z norelro -z execstack -o winner
(More code will be added later on so tags like fno-stack-protector are there)
I executed the project with argument "HELLO" and I set a break point on f->fp() and inspect the heap memory:
Everything after the first malloc() makes sense but I'm kinda puzzled about what happened after the second malloc(). The second chunk should only request 4 bytes of memory to store the function pointer but instead it took 12 bytes, which reflects on what is stored on the address 0x804a04c (4 bytes of metadata + 12 bytes of requested memory + status bit 1 = 17 => 0x00000011).
And as you can see, the function pointer did only take up four bytes on 0x804a050 with the address of nowinner (0x080484a1).
I read up on this SO post and this article but it seems it still can't explain why.
Your initial question can be answered very easily by printing sizeof of your pointer. You will not see a 12 here.
The answer to your question "Why is function pointer 12 bytes long?" is simply: "It's not!"
But your question describes a different underlying question:
"Why does allocating 4 bytes take 12 bytes on the heap?"
You are under the wrong impression that memory allocation only takes exactly what is needed to store the user data.
This is wrong.
Memory management also needs to store some management data for each allocation.
When you call free the runtime library needs to know the size of the allocated block.
Therefore you can take it as granted that every allocation consumes more memory than the requested amount.
Depending on the implementation of the heap this can be within the heap itself or in a separate area.
You can also not rely on taking the same amount of overhead for each allocation. There are weird implementation out there.
Some implementations take the requested amount and add fixed length of management data.
Some implementations use a buddy system and follow a sequence of fibonacci numbers to determine smallest suitable block size.
This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 5 years ago.
Hi all I am really new to C (just started this week), and want to make sure that I am not looking down the wrong rabbit home and hoping to perhaps get pointed to the right rabbit hole.
I create a struct:
#define MAX 64
#define ARRAY_SIZE 2048
struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char arr[ARRAY_SIZE][MAX]; // Creates an array of 2048 cells with string of length 63 max
};
int main(){
...
...
int variable = 30;
struct object l[variable]; //This is where the crash happens. But only when either variable is too large (for instance works on 15 just fine, but anything over 20 it crashes), or when Array_SIZE is too larger, for instance works fine with 1024 but 2048 crashes.
...
...
}
The error I get on crash is the following: Process returned -1073741571 (0xC00000FD) in the cmd window. And the following in the debugger in the IDE:
Program received signal SIGSEGV, Segmentation fault.
[Inferior 1 (process 12120) exited with code 030000000375]
Am I doing something obviously wrong with how I declare an array of structs? Why would large numbers not work but lower numebrs work?
Does the above error indicate I am accessing something out of bounds somewhere? Ive been up and down the code and cant seem to find any reason why larger numbers dont work and lower ones do. My memory footprint doesnt seem to be the issue, just a few megs of memory.
I need help with what to look for (I cant find any instances of accessing anything out of bounds, so I get the feeling Im not chasing the right rabbit and need to look for something else)? Or maybe Im doing something illegal for C without knowing it?
I think your program crashes because you statically allocate too much memory on the stack.
Try using the malloc or calloc function. It dynamically allocates memory on the heap instead e.g. :
struct object *l = malloc(variable*sizeof(struct object));
Don't forget to free it afterwards using the free function.
free(l);
You have a memory size problem, try to increase the memory size for your program.
And if you want to use big array size and so allocate a lot of memory, you shouldn't allocate statically but dynamically.
So you should use malloc
typedef struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char arr[ARRAY_SIZE][MAX];
} myObject ;
int variable = 30;
myObject *l = malloc(sizeof(myObject) * variable);
I do not advice you to declare an array of 2048 statically, so you should initiate your struct with a function.
typedef struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char *arr[MAX];
} myObject ;
myObject *createNewObject() {
myObject *toReturn = malloc(sizeof(myObject) * variable);
if (toReturn == NULL)
return NULL;
toReturn->arr = malloc(sizeof(char) * ARRAY_SIZE);
return (toReturn);
}
void freeMyObject(myObject *objectToFree)
{
if (objectToFree && objectToFree->arr =! NULL)
free(objectToFree->arr)
if (objectToFree)
free(objectToFree)
}
void main()
{
myObject *myNewObj = createNewObject()
// You can do some stuff with myNewObj but always verify the pointers
freeMyObject(myNewObj);
}
You should also debug with valgrind when you works with malloc, so you don't have memory loss or problems.
Hope I helped
Well the problem you had is - you have used automatic memory allocation. Due to constraint of size of automatic storage your program crashed - you asked for more than you should.
So what is the solution?
Static memory allocation:
Solution being
static struct object l[variable];
Dynamic memory allocation
struct object *ptr = malloc( sizeof *ptr * variable);
The storage of these allocation is different from automatic variables - so free from the size constraint . In this case you have to free the dynamically allocated memory. That's why you will get around the problem you have.
Statically allocate is not a confusion free term. All these types of variable will have different scope - lifetime. Standard never mentions about stack or heap . It is the implementation that follow these to store automatically allocated memory and dynamically allocated memory.
I came across a concept which some people call a "Struct Hack" where we can declare a pointer variable inside a struct, like this:
struct myStruct{
int data;
int *array;
};
and later on when we allocate memory for a struct myStruct using malloc in our main() function, we can simultaneously allocate memory for our int *array pointer in same step, like this:
struct myStruct *p = malloc(sizeof(struct myStruct) + 100 * sizeof(int));
p->array = p+1;
instead of
struct myStruct *p = malloc(sizeof(struct myStruct));
p->array = malloc(100 * sizeof(int));
assuming we want an array of size 100.
The first option is said to be better since we would get a continuous chunk of memory and we can free that whole chunk with one call to free() versus 2 calls in the latter case.
Experimenting, I wrote this:
#include<stdio.h>
#include<stdlib.h>
struct myStruct{
int i;
int *array;
};
int main(){
/* I ask for only 40 more bytes (10 * sizeof(int)) */
struct myStruct *p = malloc(sizeof(struct myStruct) + 10 * sizeof(int));
p->array = p+1;
/* I assign values way beyond the initial allocation*/
for (int i = 0; i < 804; i++){
p->array[i] = i;
}
/* printing*/
for (int i = 0; i < 804; i++){
printf("%d\n",p->array[i]);
}
return 0;
}
I am able to execute it without problems, without any segmentation faults. Looks weird to me.
I also came to know that C99 has a provision which says that instead of declaring an int *array inside a struct, we can do int array[] and I did this, using malloc() only for the struct, like
struct myStruct *p = malloc(sizeof(struct myStruct));
and initialising array[] like this
p->array[10] = 0; /* I hope this sets the array size to 10
and also initialises array entries to 0 */
But then again this weirdness where I am able to access and assign array indices beyond the array size and also print the entries:
for(int i = 0; i < 296; i++){ // first loop
p->array[i] = i;
}
for(int i = 0; i < 296; i++){ // second loop
printf("%d\n",p->array[i]);
}
After printing p->array[i] till i = 296 it gives me a segmentation fault, but clearly it had no problems assigning beyond i = 9.
(If I increment 'i' till 300 in the first for loop above, I immediately get a segmentation fault and the program doesn't print any values.)
Any clues about what's happening? Is it undefined behaviour or what?
EDIT: When I compiled the first snippet with the command
cc -Wall -g -std=c11 -O struct3.c -o struct3
I got this warning:
warning: incompatible pointer types assigning to 'int *' from
'struct str *' [-Wincompatible-pointer-types]
p->array = p+1;
Yes, what you see here is an example of undefined behavior.
Writing beyond the end of allocated array (aka buffer overflow) is a good example of undefined behavior: it will often appear to "work normally", while other times it will crash (e.g. "Segmentation fault").
A low-level explanation: there are control structures in memory that are situated some distance from your allocated objects. If your program does a big buffer overflow, there is more chance it will damage these control structures, while for more modest overflows it will damage some unused data (e.g. padding). In any case, however, buffer overflows invoke undefined behavior.
The "struct hack" in your first form also invokes undefined behavior (as indicated by the warning), but of a special kind - it's almost guaranteed that it would always work normally, in most compilers. However, it's still undefined behavior, so not recommended to use. In order to sanction its use, the C committee invented this "flexible array member" syntax (your second syntax), which is guaranteed to work.
Just to make it clear - assignment to an element of an array never allocates space for that element (not in C, at least). In C, when assigning to an element, it should already be allocated, even if the array is "flexible". Your code should know how much to allocate when it allocates memory. If you don't know how much to allocate, use one of the following techniques:
Allocate an upper bound:
struct myStruct{
int data;
int array[100]; // you will never need more than 100 numbers
};
Use realloc
Use a linked list (or any other sophisticated data structure)
What you describe as a "Struct Hack" is indeed a hack. It is not worth IMO.
p->array = p+1;
will give you problems on many compilers which will demand explicit conversion:
p->array = (int *) (p+1);
I am able to execute it without problems, without any segmentation faults. Looks weird to me.
It is undefined behaviour. You are accessing memory on the heap and many compilers and operating system will not prevent you to do so. But it extremely bad practice to use it.
typedef struct Model
{
int recordId;
char *name;
}Model;
typedef struct ModelArray
{
//keeps the size that the array was initially create with. When more elements are needed
//we use this to add that many more elements
int originalSize;
//total number of elements that can be used
int elements;
//total number of elements used
int count;
//the actual array is stored here
Model *source;
}ModelArray;
void initModelArray(ModelArray *array, int numberOfElements)
{
array->originalSize = numberOfElements;
array->elements = numberOfElements;
array->count = 0;
array->source = malloc(sizeof(Model)*numberOfElements);//0 bytes in 3 blocks are definitely lost in loss record 1 of 65
}
void deallocModelArray(ModelArray *array)
{
if(array == NULL)
return;
array->elements = 0;
array->count = 0;
free(array->source);
array->source = NULL;
free(array);
}
main(int argc, const char * argv[])
{
ModelArray *models = malloc(sizeof(ModelArray));
initModelArray(models, 10);
deallocModelArray(models);
}
What is lost? Code looks fine to me. I'm sure I could say array->source = NULL first but it's not needed, right?
To deallocate these structures correctly, you need to do the following, in this order:
free(models->source);
free(models);
If you do anything else, you're leaking memory.
Edit:
OK, having seen the Model struct, you're probably leaking the names, or at least valgrind thinks you do because you deallocate the ModelArray structure, which contains a pointer to a Model structure, which contains a char* which you don't free first.
So:
int i;
for( i=0; i<models->originalSize; i++ ) {
if( models->source[i]->name != NULL ) {
free( models->source[i]->name );
}
}
free(models->source);
free(models);
And it would be a good idea to use calloc() instead of malloc() when allocating models->source in the first place. This will set all the name pointers to 0. Without this, the test for models->source[i]->name being non-NULL above might fail if name happens to contain some garbage (since using uninitialized memory produces undefined behavior.)
Er... Yes, the memory is lost. Of course, it is lost, since you "left out dealloc code"!
How could you possibly expect anyone to answer your question when you "left out dealloc code"? The very essence of your question is whether your dealloc code is correct or not. And you decided to leave it out?
On top of that, there quite a few thing that make little sense in your code. What is
typedef struct ModelArray {
...
Model *source;
...
} Model;
supposed to mean? Why are you typedefing struct ModelArray as Model? In fact, your code will not even compile, since Model * is used inside the struct, where it is not declared yet. You also use ModelArray type in your code, while in reality there's no such type. You have struct ModelArray, but not just ModelArray. The code you posted is not real code. Post real code, please. (Apparently it was supposed to be typedef struct ModelArray { ... } ModelArray; with Model defined elsewhere.)
Finally, as an unrelated note, // comments is a C99 feature. In C99 the function return type cannot be omitted (no "implicit int" rule in C99), meaning that you have to declare your main function as int main.