sethlearn
sethlearn

Reputation: 87

Why am I not exiting this while loop?

I'm trying to make a little program to calculate standard deviation for practice. My problem seems to be the first while statement in my main function.

I’m a little rusty at this and I can’t figure out why I don’t leave the while statement after the user hits enter.

Don’t mind my greenness. Still learning.

#include <stdio.h>
#include <math.h>
#define arraySize 100
double standardDeviation(int, double*);
int main(void){
    double array[arraySize];
    double result;
    int i=0;
    int count=0;
    printf("Enter up to %d data separated by spaces then hit enter:\n\n",arraySize);
    while(i<arraySize && array[i]!='\n'){
        scanf("%lf",&array[i]);
            i++;
            count++;
            }

    result=standardDeviation(count, array);

    printf("The standard deviation of your data is: %lf",result);

    return 0;
}

double standardDeviation(int count, double* firstDatum){
    int i=0,j=0;
    double standDev=0;
    double standDevArray[arraySize];
    double sum=0,sum2=0;
    double mean=0,variance=0;
    while(i<count){
        sum=sum + firstDatum[i]; 
        //printf("%lf", sum);
        i++;
    }
    mean=sum/count;
    //printf("The mean is: %lf", mean);

    while(j<count){
           standDevArray[j] = (mean  - firstDatum[j]) * (mean - firstDatum[j]);
           sum2=sum2+standDevArray[j];
           j++;
    }   
    variance=sum2/count;
    standDev=sqrt(variance);
    return standDev;
 }

Upvotes: 4

Views: 151

Answers (3)

David C. Rankin
David C. Rankin

Reputation: 84521

There is no reason to ask the user for the number of entries. You ask the user for a line of input, you read the line of input into a buffer using fgets (or POSIX getline), you then scan through the buffer converting the numbers entered into double values using either strtod (preferred), or using sscanf and an offset to the next value to read.

You have done a good job protecting your array bounds with while (i < arraySize ..., all you need to do is add a second condition while a valid conversion is preformed. For example:

#define MAXC 2048
...
int main(void) {

    char buf[MAXC];                     /* buffer to hold line of input */
    double array[arraySize], result;    /* your array and result */
    int i = 0, offset = 0, used;        /* i, offset in buf, chars used */

    printf ("Enter up to %d data separated by spaces then hit enter:\n\n",
            arraySize);
    if (!fgets (buf, MAXC, stdin)) {    /* read/validate line of input */
        fputs ("(user canceled input)\n", stderr);
        return 1;
    }

    while (i < arraySize && /* while in bounds && valid conversion */
            sscanf (buf + offset, "%lf%n", &array[i], &used) == 1) {
        offset += used;     /* update offset with chars used in conversion */
        i++;                /* increment index */
    }

    result = standardDeviation (i, array);  /* compute/display result */

    printf ("The standard deviation of your data is: %lf\n",result);

    return 0;
}

Now you simply display your prompt, the user enters up to 100 values, and you read the values into your array and preform you calculations. Here the buffer size of 2K allows ~19-characters per-value. If that is insufficient, then use a 4K buffer and provide for ~40-chars per-value.

Additionally, there is no need for your stdDevArray or to declare separate loop counter variables in your standardDeviation() function. Since C99, you can declare the loop variable as part of the loop definition. There is nothing wrong with using the stdDevArray, it is simply not required. Spacing your code in a consistent manner also helps with the readability. If you eliminate the separate loop variables and the unneeded stdDevArray, you can tweak your function as follows:

double standardDeviation (int count, double *firstDatum)
{
    double  standDev = 0,
            sum = 0, sum2 = 0,
            mean= 0, variance = 0;

    for (int i = 0; i < count; i++)
        sum += firstDatum[i]; 

    mean = sum / count;

    for (int i = 0; i < count; i++)
        sum2 += (mean  - firstDatum[i]) * (mean - firstDatum[i]);

    variance = sum2 / count;
    standDev = sqrt(variance);

    return standDev;
}

Note the += operator is just a short-hand convenience operator. Instead of writing sum = sum + firstDatum[i];, you can simply write sum += firstDatum[i];

Let me know if you have further questions.

Upvotes: 1

sethlearn
sethlearn

Reputation: 87

I made the following adjustments to the main function. I simply predetermined the number of data entries based on the user input, and it works fine. It’s comforting to know that my function worked on it’s first call and gave me the correct value for standard deviation.

But a little discomforting to know i had to ask user for the amount of entries. I think the program would be a little more user friendly if i could enter data and then terminate when i reach the end of the list. Especially with larger data sets that a person doesn’t know how many data they are entering. It’s a little tough to use arrays with option of terminating with a value outside of bounds, because limiting the values of the entries also limits the functionality of the function. Do think if someone wanted to make a program such as this, linked lists would be more suited to this?

#include <stdio.h>
#include <math.h>
#define arraySize 100
double standardDeviation(int, double);
int main(void){
    double array[arraySize];
    double result;
    int userSize;
    int i=0;
    int count=0;
    printf("Enter how many data will be entered up to a maximum of %d\n\n",arraySize);
    scanf("%d",&userSize);
    printf("Enter your data:\n\n");
        while(i<userSize && i<arraySize){
        scanf("%lf",&array[i]);
            i++;
            count++;
            }


    result=standardDeviation(count, array);

    printf("The standard deviation of your data is: %lf",result);


    return 0;
}

    double standardDeviation(int count, double* firstDatum){
        int i=0,j=0;
        double standDev=0;
        double standDevArray[arraySize];
        double sum=0,sum2=0;
        double mean=0,variance=0;
        while(i<count){
            sum=sum + firstDatum[i]; 
            //printf("%lf", sum);
            i++;
        }
        mean=sum/count;
        //printf("The mean is: %lf", mean);

        while(j<count){
               standDevArray[j] = (mean  - firstDatum[j]) * (mean - firstDatum[j]);
               sum2=sum2+standDevArray[j];
               j++;
        }   
        variance=sum2/count;
        standDev=sqrt(variance);
        return standDev;
     }

Upvotes: 0

Zig Razor
Zig Razor

Reputation: 3495

2 errors in this piece of code, one of there causes an Undefined Behavior.

First of all you compare a double(array[i]) with a char ('\n').

The second one is the index "i". In the while loop you first do scanf and assign the i-th element of the array, the increment i with the operation i++ e after that in next iteration you compare a not initialized i-th element of the array with somenthing. Pay attention at the moment of comparison your index is already incremented and you do not assign nothing to that element and this causes an undefined behavior.

Upvotes: 0

Related Questions