Pointer array contents wiped when passed to a function in C - c

so I am loading lines of floats from text files and storing them in a pointer array, before saving them back to a text file and adding a reference to their size. The number of values in the text file varies so the array must be dynamic. I define my pointer array in main like this.
size_t size = (int)100 * sizeof(float);
float * val = malloc(size);
I then pass the pointer array to a function that loads the text file and saves the values to it, like this.
//Read file into array.
int readFile(float *val, int size) {
char buf[20] = { 0 };
val[0] = 0;
double temp = 0;
int i = 1;
FILE *file;
file = fopen("C:\\Users\\MoldOffice\\Dropbox\\VS\\finalproj\\ecgproject\\dataStream", "r");
if (!file) {
printf("Coulding find file.\n");
exit(1);
}
while (fgets(buf, 20, file) != NULL) {
temp = atof(buf);
if (temp != 0) {
// Increment i to find the size of the useful data.
val[i] = temp;
//printf("%d",val[i]);
i++;
if (i == size / sizeof(float)) {
size += 100*sizeof(float);
double* val_temp = realloc(val, size);
if (val_temp == NULL) {
printf("Realloc failed.\n");
}
else {
val = val_temp;
}
}
}
}
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
return(i);
fclose(file);
This works fine and when I print the contents of the pointer array back in main, it works. I then pass the same pointer array to another function which saves the array in a new text file, along with the size on the first line, the problem is that when I pass the pointer array for a second time, the contents have changed (mostly 0 with some random numbers). I have absolutely no idea why this is happening.. Any ideas? The function that writes the file is here:
// Write file into array.
void writeFile(float *val,int size) {
printf("%d",sizeof(val));
FILE *file;
int sampleNum;
char buf[10];
file = fopen("sampleNum.txt", "r");
if (file == NULL) { sampleNum = 0; }
else { fscanf(file, "%d", &sampleNum); printf("%d",sampleNum);}
char fileString[10];
sprintf(fileString,"sample%d\0", sampleNum);
file = fopen(fileString, "w");
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
//Print the array to a text file and save.
fprintf(file, "%d\n", size);
for (int i = 1; i < size; i++) {
fprintf(file, "%f\n", val[i]);
printf("%f\n", val[i]); }
fclose(file);
}
The rest of main can be found here:
int main() {
size_t size = (int)100 * sizeof(float);
float * val = malloc(size);
// Read the data into an array.
int arraySize = readFile(val, size);
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
// Save the array to a text file, with the size of the array as the first element.
writeFile(val,arraySize);
}

double* val_temp = realloc(val, size);
if (val_temp == NULL) {
printf("Realloc failed.\n");
}
else {
val = val_temp;
The caller of this function has no way to know that you've moved the array to a different place. It's still got the old, now invalid, pointer.
You have a similar problem with size. How does the caller know you changed it?
You choice of division of responsibilities is poor. If the caller is responsible for allocating the buffer, then this function should ask the caller to enlarge it. If this function is responsible for allocating the buffer, it should allocate it. It's generally a very bad idea to split up the responsibility for managing the allocation of a chunk of memory, and this shows one of the reasons why.
Perhaps pass in a pointer to a structure that contains a pointer to a buffer and its size? That will work, but still shows poor division of responsibilities.
Perhaps have this function allocate the buffer and return a structure that includes a pointer to it and the number of elements in it?
If you really want to to do things this way, consider passing the function a pointer to a structure that includes a pointer to the array, the size of the array, and a pointer to a function that resizes the array. The caller can, of course, set this pointer to point to the realloc function (though it's probably better for it to be a function that changes the pointer and size members of the structure).
You could also use code like this:
struct float_buffer
{
float* buffer;
int size;
};
struct float_buffer allocate_float_buffer(int size)
{
struct float_buffer buf;
buf.buffer = malloc (size * sizeof(float));
buf.size = size;
return buf;
}
bool resize_float_buffer(struct float_buffer* buf, int size)
{
float* tmp = realloc(buf->buffer, size * sizeof(float));
if (tmp == NULL)
return false;
buf->buffer = tmp;
buf->size = size;
return true;
}
And then pass the function a struct float_buffer *.

Related

Creating and returning multi-dimensional arrays

I read on some ways to dynamically create and use a 2D array, and I've settled on this way:
file:
5 4
+---+
|xxx|
|xxx|
+---+
main.c:
char** loadArray() {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w &h);
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose();
return buf;
}
int main() {
char** array = loadArray();
for (int i = 0; i < 4; i++) { // magic number, only because I know the size
printf("%s\n", array[i]);
}
return 0;
}
While this does compile, it gives a warning: incompatible pointer types returning 'char (*)[w]' from a function with result type 'char **', and segfaults if I try to run it.
Several questions (mainly for C, but C++ specific answers are welcome for future reference, when I get there):
What is the correct return type for a multidimensional array? The warning isn't quite helpful I think, since it offers a variable term, which I obviously don't have until I read the file.
At this point, I'm just trying to get returning 2D arrays to work, but when I do and move on, I'm going to need the dimensions of the array for proper usage later on. My first idea would be to return structs instead, where I can save the dimension and the array itself. However, after further thought, the variable size makes me think that I wouldn't be able to have a single struct template to use as the function's return type, and I would have to find some other way to get the size along with the array. Are ideas?
Thank you for your time.
Pointer to pointer and pointer to array are quite different things. You can't return the array dimension as such in the return type so you'd have to use an incomplete array:
char (*(loadArray()))[] {
...
}
Evidently this is not very readable so you'd better pass through a typedef:
typedef char line[];
line* loadArray() {
...
}
You'd also have to get your hands on the dimensions w and h, so you'd have to pass pointers to the values as arguments. But that would be another question.
What is the correct return type for a multidimensional array?
There is no "correct" type, it all depends on how you want to represent the data and what architecture you want to design.
The warning isn't quite helpful I think, since it offers a variable term
The warning is very helpful, because it indicates an error in the code - you are casting a pointer to an array to a pointer to a pointer. Ignoring that warning ultimately leads to printf("%s\n", array[i]); which is undefined behavior.
Are ideas?
You may return a pointer to a dynamically allocated array of pointers to dynamically allocated array of values.
char **loadArray(void) {
size_t w, h;
// Initialize w and h.
char **arr;
arr = malloc(w * sizeof(*arr));
if (!arr) return NULL;
for (size_t i = 0; i < w; ++i) {
arr[i] = malloc(h * sizeof(*arr[i]));
if (!arr[i]) {
for (size_t j = 0; j < i; ++j) {
free(arr[j]);
}
frer(arr);
return NULL;
}
}
// Fill arr from file. Handle errors. Handle deallocation.
return arr;
}
which is the usual way to program in C and one would expect char ** to act that way. I can thing of an example from POSIX , where scandir function takes a pointer to a double pointer struct dirent ***namelist argument which is assigned to a such dynamically allocated 2d array.
But let's take a bit over-engineered (or not) design (in mostly C-ish pseudocode):
// represents the thing
struct thething_s {
char *string;
};
int thething_print(struct thething_s *t, FILE *f) {
return fprintf(f, ....);
}
void thething_free(struct thething_s *t) {
free(t->string);
}
int thething_load_from_file(struct thething_s *t, FILE *f, size_t len) {
t->string = malloc(len);
if (!t->string) return -1;
if (scanf(....) != 1) return -2;
return 0;
}
// represents an array of things
struct thingsarr_s {
struct thethings_s *things;
size_t w;
size_t h;
};
int thigsarr_load_from_file(struct thingsarr_s *t, FILE *f) {
// Initialize t->w and t->h.
t->things = malloc(t->w * sizeof(*t->things));
if (!arr) return -1;
for (size_t i = 0; i < w; ++i) {
if (thething_load_from_file(&t->things[i], f, t->h) != 0) {
for (size_t j = 0; j < i; ++j) {
thethings_free(t->things[j]);
}
free(t->things);
return -1000 - i;
}
}
return 0;
}
const struct thething_s *thingsarr_get_thing(const struct thingsarr_s *t, size_t idx)
{
assert(idx < t->len);
return t->things[idx];
}
struct thething_s *thingsarr_get_thing_nonconst(struct thingsarr_s *t, size_t idx) {
return (struct thething_s *)thingsarr_get_thing(t, idx);
}
void thingsarr_free(struct thingsarr_s *t) {
for (.,.) {
thething_free(&t->things[i]);
}
free(t->things);
}
Which is "best" strongly depends on the context, specific needs and specific application.
The pointer types char ** and char (*)[w] are very different. There is a common misconception that arrays and pointers are the same thing in C, but that is not the case.
You want the return type of the function to be char (*)[w], but that return type is impossible to declare because w is an unknown value. Also, the caller doesn't know the width and height of the returned array, because that information is internal to the loadArray function.
Setting the return type of the loadArray function to void* allows it to just return a pointer to the array without knowing the width or height. The width and height values can be sent to the caller using pointer arguments so that the caller can reconstruct the array type.
The following modifications of the original C code implements the above change. (C++ does not support variable length array types as far as I know, so this is C only.)
#include <stdio.h>
#include <stdlib.h>
void* loadArray(int *pw, int *ph) {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w, &h);
*pw = w;
*ph = h;
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose(in);
return buf;
}
int main(void) {
int w, h;
void* larray = loadArray(&w, &h);
char(*array)[w] = larray;
for (int i = 0; i < h; i++) {
printf("%s\n", array[i]);
}
return 0;
}

dynamic char pointers array to strings

in this code I want to get a number of friends and then get the names i want the strings will be allocated dynamically with the lengh of the user input i have used with 2 functions:
void getNum(char** names, int* num)
{
//somecode
names = (char*)malloc(*num * sizeof(char));
//check
}
void getNames(char** names, int* num)
{
int i = 0;
int len = 0;
char name[LEN] = { 0 };
getchar(); //buffer cleaning
for (i = 0; i < *num; i++)
{
printf("enter #%d friend name: ", i+1);
myFgets(name, LEN); //getting name and cleaning "\n" at end
len = strlen(name)+1; // getting the size of string include "/0"
*(names + i) = (char*)malloc(len * sizeof(char));
if (*(names[i]) == NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(*names, name, len);
}
}
the second dynamic allocation doens't work for me, overflow eror: "Access violation writing location". If the first allocation will be in the second function it will work fine. Can u explain that? and what I need to do for it will work in that way?
thank you in advance...
In function getNames, you used the wrong pointer to check for NULL, names[i] is *(names+i), not the same as *(names[i]), also, don't cast malloc's return value. No need to use sizeof(char), it's always 1.
*(names + i) = (char*)malloc(len * sizeof(char));
if (*(names[i]) == NULL) // compare to the wrong pointer
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(*names, name, len); // copy to the wrong buffer
Try the following:
names[i] = malloc(len);
if (names[i] == NULL)
{
printf("Error allocating memory!\n");
return 1; //return with failure
}
strncpy(names[i], name, len);
Also, in getNum, to allocate an array for char pointers, use
void getNum(char ***names, int *num) {
*names = malloc(*num * sizeof(char*));
}
You will call it by
char **names;
getNum(&names, &num);
You could also return it by doing char **getNum(...).
Assuming the first function should allocate an array of pointers, and that the second should allocate individual char arrays to store the individual names, you are lacking an indirection level in first function:
you pass it a copy of a char** (C pass parameters by copy)
you only use the local copy to store the result of the malloc (which is wrong BTW) and still keep original value in caller and eventually get a memory leak when leaving the function since nothing points to the allocated block any longer
It should be:
char** getNum(int num) /* no need to pass num by reference */
{
char **names;
//somecode
names = malloc(num * sizeof(char*)); /* do not cast resul of malloc in C */
//check
return names
}
And in second function, you should consistenly allocate memory for names[i] (or *(names + i)), test it for NULL and copy the string there:
names[i] = malloc(len * sizeof(char));
if (names[i] == NULL)
{
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
}
strncpy(names[i], name, len);

Passing pointer of pointers to function, returning both an int and an address (by parameter)

I've got a function which, as is, works correctly. However the rest of the program has a limitation in that I've preset the size of the array (the space to be allocated). Obviously, this is problematic should an event arise in which I need extra space for that array. So I want to add dynamic allocation of memory into my program.
But I'm having an issue with the whole pointer to a pointer concept, and I've utterly failed to find an online explanation that makes sense to me...
I think I'll want to use malloc(iRead + 1) to get an array of the right size, but I'm not sure what that should be assigned to... *array? **array? I'm not at all sure.
And I'm also not clear on my while loops. &array[iRead] will no longer work, and I'm not sure how to get a hold of the elements in the array when there's a pointer to a pointer involved.
Can anyone point (heh pointer pun) me in the right direction?
I can think of the following approaches.
First approach
Make two passes through the file.
In the first pass, read the numbers and discard them but keep counting the number of items.
Allocate memory once for all the items.
Rewind the file and make a second pass through it. In the second pass, read and store the numbers.
int getNumberOfItems(FILE* fp, int hexi)
{
int numItems = 0;
int number;
char const* format = (hexi == 0) ? "%X" : "%d";
while (fscanf(fp, format, &number) > 0) {
++numItems;
return numItems;
}
void read(int *array, FILE* fp, int numItems, int hexi)
{
int i = 0;
char const* format = (hexi == 0) ? "%X" : "%d";
for ( i = 0; i < numItems; ++i )
fscanf(fp, format, &array[i]);
}
int main(int argc, char** argv)
{
int hexi = 0;
FILE* fp = fopen(argv[1], "r");
// if ( fp == NULL )
// Add error checking code
// Get the number of items in the file.
int numItems = getNumberOfItems(fp, hexi);
// Allocate memory for the items.
int* array = malloc(sizeof(int)*numItems);
// Rewind the file before reading the data
frewind(fp);
// Read the data.
read(array, fp, numItems, hexi);
// Use the data
// ...
// ...
// Dealloate memory
free(array);
}
Second approach.
Keep reading numbers from the file.
Every time you read a number, use realloc to allocate space the additional item.
Store the in the reallocated memory.
int read(int **array, char* fpin, int hexi)
{
int number;
int iRead = 0;
// Local variable for ease of use.
int* arr = NULL;
char const* format = (hexi == 0) ? "%X" : "%d";
FILE *fp = fopen(fpin, "r");
if (NULL == fp){
printf("File open error!\n");
exit(-1);
}
while (fscanf(fp, format, &number) > 0) {
arr = realloc(arr, sizeof(int)*(iRead+1));
arr[iRead] = number;
iRead += 1;
}
fclose(fp);
// Return the array in the output argument.
*array = arr;
return iRead;
}
int main(int argc, char** argv)
{
int hexi = 0;
int* array = NULL;
// Read the data.
int numItems = read(&array, argv[1], hexi);
// Use the data
// ...
// ...
// Dealloate memory
free(array);
}
int read(int **array, char* fpin, int hexi) {
int iRead = 0;
int i, *ary;
char *para;
FILE *fp;
fp = fopen(fpin, "r");
if (NULL == fp){
printf("File open error!\n");
exit(-1);
}
para = (hexi == 0) ? "%*X" : "%*d";
while (fscanf(fp, para)!= EOF)
++iRead;
ary = *array = malloc(iRead*sizeof(int));
if(ary == NULL){
printf("malloc error!\n");
exit(-2);
}
rewind(fp);
para = (hexi == 0) ? "%X" : "%d";
for(i = 0; i < iRead; ++i)
fscanf(fp, para, &ary[i]);
fclose(fp);
return iRead;
}
I'd suggest something like this:
int read(int **array_pp, char* fpin, int hexi) {
...
int *array = malloc (sizeof (int) * n);
for (int i=0; i < n; i++)
fscanf(fp, "%X",&array[i]);
...
*array_pp = array;
return n;
}
Notes:
1) You must use "**" if you want to return a pointer in a function argument
2) If you prefer, however, you can declare two pointer variables (array_pp and array) to simplify your code.
I think you wouldn't call it an array. Arrays are of fixed size and lie on the stack. What you need (as you already said), is dynamically allocated memory on the heap.
maybe that's why you didn't find much :)
here are some tutorials:
http://en.wikibooks.org/wiki/C_Programming/Arrays (and following pages)
http://www.eskimo.com/~scs/cclass/int/sx8.html
you got the function declaration correctly:
int read(int **array, char* fpin, int hexi)
What you need to do:
find out how much memory you need, eg. how many elements
allocate it with *array = malloc(numElements * sizeof(int)) (read "at the address pointed by array allocate memory for numElements ints")
now you can (*array)[idx] = some int (read "at the address pointed by array, take the element with index idx and assign some int to it")
call it with int* destination; int size = read(&destination, "asdf", hexi)
hope it helps..

How could I write the content of a array of pointers to a file using fwrite?

void write(const record* list[])
{
FILE* out=fopen("output.txt","w");
if(!out)
{
printf("error"); exit(1);
}else
{
}
}
fwrite takes a array as the first argument, but my array is a array of pointers. I want the content of the pointer pointing to written to the file. How could I manage it?
int i;
for (i = 0; i < length; i++)
{
fwrite(list[i], sizeof (record), 1, out) ;
}
where length is the size of the array. You must modify your program and pass the length to your write function.

How to allocate and deallocate heap memory for 2D array?

I'm used to PHP, but I'm starting to learn C. I'm trying to create a program that reads a file line by line and stores each line to an array.
So far I have a program that reads the file line by line, and even prints each line as it goes, but now I just need to add each line to an array.
My buddy last night was telling me a bit about it. He said I'd have to use a multidimensional array in C, so basically array[x][y]. The [y] part itself is easy, because I know the maximum amount of bytes that each line will be. However, I don't know how many lines the file will be.
I figure I can make it loop through the file and just increment an integer each time and use that, but I feel that there might be a more simple way of doing it.
Any ideas or even a hint in the right direction? I appreciate any help.
To dynamically allocate a 2D array:
char **p;
int i, dim1, dim2;
/* Allocate the first dimension, which is actually a pointer to pointer to char */
p = malloc (sizeof (char *) * dim1);
/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars
* within each of these arrays are chars
*/
for (i = 0; i < dim1; i++)
{
*(p + i) = malloc (sizeof (char) * dim2);
/* or p[i] = malloc (sizeof (char) * dim2); */
}
/* Do work */
/* Deallocate the allocated array. Start deallocation from the lowest level.
* that is in the reverse order of which we did the allocation
*/
for (i = 0; i < dim1; i++)
{
free (p[i]);
}
free (p);
Modify the above method. When you need another line to be added do *(p + i) = malloc (sizeof (char) * dim2); and update i. In this case you need to predict the max numbers of lines in the file which is indicated by the dim1 variable, for which we allocate the p array first time. This will only allocate the (sizeof (int *) * dim1) bytes, thus much better option than char p[dim1][dim2] (in c99).
There is another way i think. Allocate arrays in blocks and chain them when there is an overflow.
struct _lines {
char **line;
int n;
struct _lines *next;
} *file;
file = malloc (sizeof (struct _lines));
file->line = malloc (sizeof (char *) * LINE_MAX);
file->n = 0;
head = file;
After this the first block is ready to use. When you need to insert a line just do:
/* get line into buffer */
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1));
n++;
When n is LINE_MAX allocate another block and link it to this one.
struct _lines *temp;
temp = malloc (sizeof (struct _lines));
temp->line = malloc (sizeof (char *) * LINE_MAX);
temp->n = 0;
file->next = temp;
file = file->next;
Something like this.
When one block's n becomes 0, deallocate it, and update the current block pointer file to the previous one. You can either traverse from beginning single linked list and traverse from the start or use double links.
There's no standard resizable array type in C. You have to implement it yourself, or use a third-party library. Here's a simple bare-bones example:
typedef struct int_array
{
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array)
{
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array)
{
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_push_back(int_array *array, int value)
{
if(array->length == array->capacity)
{
// Not enough space, reallocate. Also, watch out for overflow.
int new_capacity = array->capacity * 2;
if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int))
{
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if(new_array != NULL)
{
array->array = new_array;
array->capacity = new_capacity;
}
else
; // Handle out-of-memory
}
else
; // Handle overflow error
}
// Now that we have space, add the value to the array
array->array[array->length] = value;
array->length++;
}
Use it like this:
int_array a;
int_array_init(&a);
int i;
for(i = 0; i < 10; i++)
int_array_push_back(&a, i);
for(i = 0; i < a.length; i++)
printf("a[%d] = %d\n", i, a.array[i]);
int_array_free(&a);
Of course, this is only for an array of ints. Since C doesn't have templates, you'd have to either put all of this code in a macro for each different type of array (or use a different preprocessor such as GNU m4). Or, you could use a generic array container that either used void* pointers (requiring all array elements to be malloc'ed) or opaque memory blobs, which would require a cast with every element access and a memcpy for every element get/set.
In any case, it's not pretty. Two-dimensional arrays are even uglier.
Instead of an array here, you could also use a linked list, The code is simpler, but the allocation is more frequent and may suffer from fragmentation.
As long as you don't plan to do much random access (Which is O(n) here), iteration is about as simple as a regular array.
typedef struct Line Line;
struct Line{
char text[LINE_MAX];
Line *next;
};
Line *mkline()
{
Line *l = malloc(sizeof(Line));
if(!l)
error();
return l;
}
main()
{
Line *lines = mkline();
Line *lp = lines;
while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){
lp->next = mkline();
lp = lp->next;
}
lp->next = NULL;
}
If you are using C you will need to implement the resizing of the array yourself. C++ and the SDL has this done for you. It is called a vector. http://www.cplusplus.com/reference/stl/vector/
While a multidimensional array can solve this problem, a rectangular 2D array would not really be the natural C solution.
Here is a program that initially reads the file into a linked list, and then allocates a vector of pointers of the right size. Each individual character does then appear as array[line][col] but in fact each row is only as long as it needs to be. It's C99 except for <err.h>.
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct strnode {
char *s;
struct strnode *next;
} strnode;
strnode *list_head;
strnode *list_last;
strnode *read1line(void) {
char space[1024];
if(fgets(space, sizeof space, stdin) == NULL)
return NULL;
strnode *node = malloc(sizeof(strnode));
if(node && (node->s = malloc(strlen(space) + 1))) {
strcpy(node->s, space);
node->next = NULL;
if (list_head == NULL)
list_head = node;
else
list_last->next = node;
list_last = node;
return node;
}
err(1, NULL);
}
int main(int ac, char **av) {
int n;
strnode *s;
for(n = 0; (s = read1line()) != NULL; ++n)
continue;
if(n > 0) {
int i;
strnode *b;
char **a = malloc(n * sizeof(char *));
printf("There were %d lines\n", n);
for(b = list_head, i = 0; b; b = b->next, ++i)
a[i] = b->s;
printf("Near the middle is: %s", a[n / 2]);
}
return 0;
}
You can use the malloc and realloc functions to dynamically allocate and resize an array of pointers to char, and each element of the array will point to a string read from the file (where that string's storage is also allocated dynamically). For simplicity's sake we'll assume that the maximum length of each line is less than M characters (counting the newline), so we don't have to do any dynamic resizing of individual lines.
You'll need to keep track of the array size manually each time you extend it. A common technique is to double the array size each time you extend, rather than extending by a fixed size; this minimizes the number of calls to realloc, which is potentially expensive. Of course that means you'll have to keep track of two quantities; the total size of the array and the number of elements currently read.
Example:
#define INITIAL_SIZE ... // some size large enough to cover most cases
char **loadFile(FILE *stream, size_t *linesRead)
{
size_t arraySize = 0;
char **lines = NULL;
char *nextLine = NULL;
*linesRead = 0;
lines = malloc(INITIAL_SIZE * sizeof *lines);
if (!lines)
{
fprintf(stderr, "Could not allocate array\n");
return NULL;
}
arraySize = INITIAL_SIZE;
/**
* Read the next input line from the stream. We're abstracting this
* out to keep the code simple.
*/
while ((nextLine = getNextLine(stream)))
{
if (arraySize <= *linesRead)
{
char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp);
if (tmp)
{
lines = tmp;
arraySize *= 2;
}
}
lines[(*linesRead)++] = nextLine;
)
return lines;
}

Resources