Since you allocate room for the flexible array member, you must know the number of shops at some point. This allows you to choose from multiple options. The ideas presented below are all functions that assume you pass the shops array itself and the extra item mentioned, where applicable:
The object_count method
You could track the number of shops added (add something like size_t shop_count; to the structure definition). Freeing the strings is as simple as:
void
free_shops(
char **shops,
size_t n)
{
while (n-- > 0)
free(my_mall->shops[n]);
}
The sentinel (terminating value) method
You could also use a sentinel value (e.g. a null pointer) as an extra member, so you'd allocate shop_count + 1 shops every time. In that regard, it's no different than the other two options since you still allocate an extra bit of memory to store the sentinel value:
void
free_shops(char **shops)
{
for (; *shops != NULL; ++shops)
free(*shops);
}
The end pointer method
Another, perhaps more complex method, is a variation of tracking the number of shops added. Since you allocated the flexible array member, you know how many shops there are at some point. All you'd need to do is add a char **end_shops; member and assign my_mall->shops + shop_count to it whenever you know the shop count. Then when you want to free the strings allocated by strdup():
void
free_shops(
char **shops,
char **end)
{
while (end-- != shops)
free(*end);
}
If you didn't have an object count, you'd be stuck with the sentinel method only as the others rely on arithmetic. Of course, if you iterated through the array to find the sentinel value, that would allow you to determine the object count, though you could just as easily free things while searching for the sentinel value, making it pointless to do so in the first place. :P