Dynamic resizing of arrays is something which is tricky even on a full-blown PC with a proper memory management layer.
On a small microcontroller with limited RAM and no real memory management it's just not really practical.
You're much better off dealing with the CSV file in chunks - be that in single lines, or blocks of a specific size.
Personally I'd write a function which opens the file and returns a "handle" to it, plus another function which returns successive lines. A third function which allows you to "seek" to a specific line is also useful, but not essential.
Finally, a "close" function to clean it all up and release any memory allocated is a must.
That way, instead of dealing with messy multi-dimentional arrays, you're just dealing with simple function calls. Something like:
int myFile = csv_open("myfile.csv");
while(csv_getline(myFile,(struct myStruct *)&data))
as an example - of course, there is 9,000,000,000 more lines of code to be written in the csv_* functions etc