0

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);

}
15
  • 1
    Please can you simplify this to a minimal test-case. For example, the code that writes the data to a file is probably irrelevant if the problem is to do with calling functions. Commented Apr 7, 2017 at 16:53
  • Search for and read about emulating pass by reference in c Commented Apr 7, 2017 at 16:55
  • will do that now. Commented Apr 7, 2017 at 16:55
  • 1
    Also, if you declare a function to return a value, it must actually return a value or you will have undefined behavior. Commented Apr 7, 2017 at 16:55
  • 2
    Your readFile is not returning anything. Warnings would tell you that. Commented Apr 7, 2017 at 16:56

1 Answer 1

3
        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 *.

Sign up to request clarification or add additional context in comments.

6 Comments

Sorry what do you mean by the caller of the function? The variable that it gets assigned to? I have no computer science background!
By "the caller of the function", I mean whatever code calls the function that contains the code I excerpted in my answer. You pass this function a pointer to a buffer and its size. But what it really needs is a pointer to the buffer, its size, and a way to resize the buffer.
Do you think I should just use realloc on val instead?
That doesn't fix anything. The caller still has no way to know that the value of val (in this function) has changed. You passed the pointer and the size by value.
Ohhh ok, I think I understand... I might need to write that down on paper and stare at it for a while.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.