1

I'm currently working on some code and, up to now, everything has compiled fine. The aim of the code is this:

  • read input from data file and assign values to an array.
  • "smooth the data" by taking average of the data on a given interval and replacing each value in that interval with the average.

It's the second part that causing me trouble. In the external function, for some reason it works when my 'for' loop looks like this:

for(i=t; i<t+z; i++)

But I don't want it to do that. I want it to do this:

for(i=t*z; i<(t+1)*z; i++)

When I try to compile, it just crashes out on me. Anyone know the reason why? It's been puzzling me for hours now. All the code is shown below by the way:

#include <stdio.h>
#include <stdlib.h>

float foo(float*, int, int);

int main(int argc, char* argv[])
{
    FILE *input;

    const char datafile[]="datainput.dat";
    input=fopen(datafile, "r");

    int i;
    int N=0, t=0;
    int z=100;
    int M=10;
    float *a, avg;

    a=(float*)malloc(M*sizeof(float));

    if((input!=(FILE*) NULL))
    {
        while(fscanf(input, "%e", &a[t++])==1)
        {
            if (t>=M)
            {
                M*=2;
                a=(float *)realloc(a, M*sizeof(float));
            }
            N++;
        }
        float u[N];

        for(t=0; t<N; t++)
        {
            avg = foo(a, z, t);
            u[t] = avg;
        }
        fclose(input);
    }
    else
        printf("Input file could not be opened.\n");

    return(0);
}

float foo(float b[], int z, int t)
{
    int i;
    int k=0;
    float avg;
    float sum=0;

    for(i=t*z; i<(t+1)*z; i++)
    {
        sum+=b[i];
        k++;
    }
    avg = sum/(float)k;

    return(avg);
}

side note: you'll probably notice the poor practise of defining float u[N] half way down the code. I don't really like this being there, but you'll note that N is a variable that counts the number of values in the input file (initially unknown) and is initally set to N=0, so I'm not sure how I get around that.

additionally, I asked the question earlier on here but my realloc has no clause if it fails. it's something i'm working on though but at the moment it compiles without it being there.

Also, all the data values are of the form float with seven decimal places and in scientific notation, hence the %e.

Thank you!


EDIT: here are some of the values from the data file. Even though the values on the left look ordered, they are actual values in the file and not there to denote the values on the right.

   8.0800000e+00   7.0872796e-01
   8.0900000e+00   7.1941101e-01
   8.1000000e+00   2.1635408e+00
   8.1100000e+00  -5.4200807e-01
   8.1200000e+00   1.1046968e+00
   8.1300000e+00   1.5833782e+00
   8.1400000e+00   6.6122899e-01
   8.1500000e+00   1.7922273e+00
   8.1600000e+00   1.2446803e+00
   8.1700000e+00   3.7869871e-01
   8.1800000e+00   1.4793635e+00
   8.1900000e+00   1.0508171e+00
   8.2000000e+00   9.1012735e-01
   8.2100000e+00   6.0967729e-01
   8.2200000e+00   1.3834455e+00
   8.2300000e+00  -5.2312924e-01
   8.2400000e+00   9.2566688e-01
   8.2500000e+00   7.8145188e-01
   8.2600000e+00   4.1410150e-01
   8.2700000e+00   1.9796986e+00
   8.2800000e+00   5.9372874e-01
   8.2900000e+00   1.8696331e+00
   8.3000000e+00   2.3058409e+00
15
  • How does it crash? A segmentation fault? If so, did you try stepping through with gdb to see what line causes the crash? Commented Jan 24, 2013 at 3:24
  • What is the error, and on what line? You also may want to make your variable names more meaningful. Commented Jan 24, 2013 at 3:26
  • I'm currently using Codeblocks and when I try to run it, it says file.exe has stopped working (like when something's not responding on Windows). Commented Jan 24, 2013 at 3:28
  • Did you miss ! in the comparison? for(i=t*z; i=(t+1)*z; i++) should be for(i=t*z; i!=(t+1)*z; i++) Commented Jan 24, 2013 at 3:28
  • Is it a compile-time error, or a run-time error? Commented Jan 24, 2013 at 3:29

3 Answers 3

1

So I've been staring at this for awhile. This is what I came up with. The interval (i'm assuming is 100). for the sake of sanity I've changed it to 5 in the code that follows because your sample posted data is only 46 elements long. I must assume yours is much larger than this.

Some things to note:

  • foo() no longer relies on some whacky 'where do I compute my average' variables. The caller is responsible for passing the starting location and count of elements to average. This, as you will see, makes that code much simpler. This was fundamentally the heart of the problem to begin with, as your allocation loop was fine (save for not checking your realloc return value). There is no reason to complicate that function to try and compute an average somewhere in the middle of some larger array. Keep it simple. Just have the caller tell the function where to start and how many to average.

  • Though it wasn't specified, I believe z is your "interval" width. The thing to note in the code below is the interval-count calculation. The number of intervals is simply (N+(z-1))/z, which will result in the number of intervals to process, including the last interval which may only be a partial. From there, we simply walk through the original array, partitioning up in z-sized slices, calculating the average, then rewriting the interval we just averaged with the said-same average. The last interval, again, can be a partial, which requires a little bit of extra care.

  • I changed the data file to be a command line parameter argv[1]. Made it easier for me to test.

Sure hope this is what you were looking for. Thx for the fun, and don't forget to reset the z value in this code back to 100 if you plan on using it.

#include <stdio.h>
#include <stdlib.h>

float foo(float a[], int count);

int main(int argc, char* argv[])
{
    if (argc !=2)
        return EXIT_FAILURE;

    FILE *input=fopen(argv[1], "r");
    if (input != NULL)
    {
        int z=5,t=0;
        int M=10,N=0;
        float *a = malloc(M*sizeof(float));

        while(fscanf(input, " %e", a + N) ==1 )
        {
            if (++N>=M)
            {
                void *tmp = realloc(a, (M*=2)*sizeof(float));
                if (tmp != NULL)
                {
                    a = tmp;
                }
                else
                {
                    perror("Failed to allocate memory.");
                    exit(EXIT_FAILURE);
                }
            }
        }

        // compute number of intervals we will process. the last
        //  interval may be only a partial.
        for (t=0;t<N;t+=z)
        {
            // how many we're doing in this interval
            int count = (z < (N-t) ? z : (N-t)), k=0;
            float avg =  foo(a+t, count);
            printf("Avg[%d] = %e\n", t/z, avg);

            // smooth over original array with just-found svg.
            for (k=0;k<count; a[t+k++] = avg);
        }
        fclose(input);

        // dump the final array content
        for (t=0;t<N;++t)
            printf("a[%d] = %e\n", t, a[t]);

        // release original array.
        free(a);
    }
    else
    {
        perror("Input file could not be opened.");
    }

    return(0);
}
// find the average of the range of floats we're given.
float foo(float a[], int count)
{
    float sum = 0;
    int i = 0;

    for(i=0; i<count; sum += a[i++]);
    return (sum)/(float)(count);
}

Output (z=5)

Avg[0] = 5.139628e+00
Avg[1] = 3.791246e+00
Avg[2] = 5.332921e+00
Avg[3] = 3.949121e+00
Avg[4] = 5.420036e+00
Avg[5] = 3.866650e+00
Avg[6] = 5.024508e+00
Avg[7] = 3.941051e+00
Avg[8] = 5.466672e+00
Avg[9] = 2.305841e+00
a[0] = 5.139628e+00
a[1] = 5.139628e+00
a[2] = 5.139628e+00
a[3] = 5.139628e+00
a[4] = 5.139628e+00
a[5] = 3.791246e+00
a[6] = 3.791246e+00
a[7] = 3.791246e+00
a[8] = 3.791246e+00
a[9] = 3.791246e+00
a[10] = 5.332921e+00
a[11] = 5.332921e+00
a[12] = 5.332921e+00
a[13] = 5.332921e+00
a[14] = 5.332921e+00
a[15] = 3.949121e+00
a[16] = 3.949121e+00
a[17] = 3.949121e+00
a[18] = 3.949121e+00
a[19] = 3.949121e+00
a[20] = 5.420036e+00
a[21] = 5.420036e+00
a[22] = 5.420036e+00
a[23] = 5.420036e+00
a[24] = 5.420036e+00
a[25] = 3.866650e+00
a[26] = 3.866650e+00
a[27] = 3.866650e+00
a[28] = 3.866650e+00
a[29] = 3.866650e+00
a[30] = 5.024508e+00
a[31] = 5.024508e+00
a[32] = 5.024508e+00
a[33] = 5.024508e+00
a[34] = 5.024508e+00
a[35] = 3.941051e+00
a[36] = 3.941051e+00
a[37] = 3.941051e+00
a[38] = 3.941051e+00
a[39] = 3.941051e+00
a[40] = 5.466672e+00
a[41] = 5.466672e+00
a[42] = 5.466672e+00
a[43] = 5.466672e+00
a[44] = 5.466672e+00
a[45] = 2.305841e+00

Output (z=10)

Avg[0] = 4.465437e+00
Avg[1] = 4.641021e+00
Avg[2] = 4.643343e+00
Avg[3] = 4.482779e+00
Avg[4] = 4.939867e+00
a[0] = 4.465437e+00
a[1] = 4.465437e+00
a[2] = 4.465437e+00
a[3] = 4.465437e+00
a[4] = 4.465437e+00
a[5] = 4.465437e+00
a[6] = 4.465437e+00
a[7] = 4.465437e+00
a[8] = 4.465437e+00
a[9] = 4.465437e+00
a[10] = 4.641021e+00
a[11] = 4.641021e+00
a[12] = 4.641021e+00
a[13] = 4.641021e+00
a[14] = 4.641021e+00
a[15] = 4.641021e+00
a[16] = 4.641021e+00
a[17] = 4.641021e+00
a[18] = 4.641021e+00
a[19] = 4.641021e+00
a[20] = 4.643343e+00
a[21] = 4.643343e+00
a[22] = 4.643343e+00
a[23] = 4.643343e+00
a[24] = 4.643343e+00
a[25] = 4.643343e+00
a[26] = 4.643343e+00
a[27] = 4.643343e+00
a[28] = 4.643343e+00
a[29] = 4.643343e+00
a[30] = 4.482779e+00
a[31] = 4.482779e+00
a[32] = 4.482779e+00
a[33] = 4.482779e+00
a[34] = 4.482779e+00
a[35] = 4.482779e+00
a[36] = 4.482779e+00
a[37] = 4.482779e+00
a[38] = 4.482779e+00
a[39] = 4.482779e+00
a[40] = 4.939867e+00
a[41] = 4.939867e+00
a[42] = 4.939867e+00
a[43] = 4.939867e+00
a[44] = 4.939867e+00
a[45] = 4.939867e+00
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you so much for this. I only expected a push in the right direction so for you give an alternative version is fantastic. I understand most of what you've got; the one problem I seem to have (when compiling) is with checking the return value of realloc. It seems to prevent me from printing anything, and instead returns 1 (this is on CodeBlocks). Do you have any idea why this? It's part of the reason why I didn't include it in the first place, as I was able to print output without it being there.
The return (1) means EXIT_FAILURE, which is not good. You're talking about the realloc() in the while loop, right? not the initial one (the malloc())? Oh, and check the code again, I had t being compared against M in the if() accidentally. It is right now in the posted code.
Did you see the comment I mentioned concerning how I changed it to take the data file as a command line parameter rather than hard-coded into the program? Note the fopen(argv[1],"r") call. If you're not passing the filename as a parameter, but rather opening a named file directly, you'll need to change that (or just passed the full-path to your data file as the sole parameter). That, btw, is the other EXIT_FAILURE point in the code.
Again, to reiterate, I cannot thank you enough. I'd say I get most of your code(there's certain things in there I wouldn't have been confident enough to use but I guess that comes with experience) but for to take the time out and right all that up is really appreciated.
So long as the numbers are what you were looking for. Offhand, how many floats are your actual data files?
|
0

It unlikely that sum+=b[i]; will access the array b between 0 and N-1.

Comments

0

You have allocated 10 block for floats which is passed as array parameter for function. In statement sum+=b[i], here b[i] will not ensure that you are not referring at the index out side the array size, as you have "i" which can go beyond 10 e.g. when z=100 and t=1.

Comments

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.