-1

Here's my code, it is supposed to calculate the standard deviation of the randomly generated array that fillArray populates. stdDev is supposed to calculate the standard deviation. otherStats is supposed to find the largest and smallest value in the array. So far, the only thing that is being generated are 0s for the deviation, smallest, and largest. Here's the code:

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


float fillArray (float array[7][5]);
float printArray (float array[7][5], float deviation, float largest, float smallest);
float stdDev (float array[7][5], float deviation, float average);
float otherStats (float array[7][5], float largest, float smallest);

int main ()
{
  float deviation, average, largest, smallest; 
  float array[7][5];
  fillArray (array);
  stdDev (array, deviation, average);
  otherStats (array, largest, smallest);
  printArray (array, deviation, largest, smallest);
}

float fillArray (float array[7][5])
{
  int row, column;
  for (row = 0; row < 7; row++)
    {
      for (column = 0; column < 5; column++)
        {
          array[row][column] = (float) rand () / (float) RAND_MAX;
        }
    }
  return array[7][5];
}

float stdDev (float array[7][5], float deviation, float average)
{
  float number1, number2;
  array[7][5] = fillArray(array);
  int ROw, Col;
  for (ROw = 0; ROw < 7; ROw++)
    {
      for (Col = 0; Col < 5; Col++)
        {
          number1 = array[ROw][Col] + number1;
          average = number1 / 35;
        }
     }

      for (ROw = 0; ROw < 7; ROw++)
        {
          for (Col = 0; Col < 5; Col++)
            {
              number2 = average - array[ROw][Col];
              deviation = sqrt (number2 / 35);
            }
        }
  return deviation;
}

float otherStats (float array[7][5], float largest, float smallest)
{
  array[7][5] = fillArray(array);
  float num1, num2;             //Check which ones largest or smallest.
  int ROW, COLUMN;
  for (ROW = 0; ROW < 7; ROW++)
    {
      for (COLUMN = 0; COLUMN < 5; COLUMN++)
        {
          num1 = array[ROW][COLUMN];
          num2 = array[1][1];
          largest = num2;
          smallest = num1;
          if (num1 > num2)
            {
              largest = num1;
            }
          else
            {
              smallest = num1;
            }
        }
    }
  return largest, smallest;
}

float printArray (float array[7][5], float deviation, float largest, float 
smallest)
{
  int Row, Column;

  printf("Column #:  ");

  for (Column = 0; Column < 5; Column++)
    {
      printf ("%d     ", Column);
    }
  printf("\nRow #|________________________________\n");

  for (Row = 0; Row < 7; Row++)
    {
      printf("%d    |   ", Row);

      for (Column = 0; Column < 5; Column++)
        {
          printf ("%4.2f  ", array[Row][Column]);
        }

      printf ("\n");
    }
  printf("The standard deviation is %f, the largest is %f, the smallest is %f.\n", 
deviation, largest, smallest);
}

Any help to figure out my error would be super appreciate. It compiles fine, it's just that my logic or something is messed up.

Thanks in advance.

This is the output:

Column #:  0     1     2     3     4     
Row #|________________________________
0    |   0.53  0.04  0.44  0.93  0.93  
1    |   0.72  0.28  0.74  0.64  0.35  
2    |   0.69  0.17  0.44  0.88  0.83  
3    |   0.33  0.23  0.89  0.35  0.69  
4    |   0.96  0.59  0.66  0.86  0.44  
5    |   0.92  0.40  0.81  0.68  0.91  
6    |   0.48  0.22  0.95  0.92  0.15  
The standard deviation is -0.000000, the largest is 0.000000, the smallest is 0.000000.
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
user2998283
  • 51
  • 1
  • 6
  • 1
    Try using the debugger. – Mitch Wheat Nov 16 '13 at 03:50
  • There are no bugs. The debugger won't help if there are no bugs, will it? – user2998283 Nov 16 '13 at 03:51
  • 4
    "There are no bugs" : then why are you here? (and there are *plenty* of bugs, btw). You need to learn how to pass out-parameters in C (i.e. by address through pointers. Find it in your book). – WhozCraig Nov 16 '13 at 03:52
  • 1
    "There are no bugs." - Really? Your question contradicts that "So far, the only thing that is being generated are 0s for the deviation" – Mitch Wheat Nov 16 '13 at 03:53
  • Look, not to be rude, but if I knew how to use the debugger and if it was effective, I wouldn't be here. The program compiles fine. The problem is within my logic and I'm sure how to fix it. Help would be appreciated. – user2998283 Nov 16 '13 at 03:54
  • 1
    By "no bugs" I mean that it compiles fine. I should have specified that. – user2998283 Nov 16 '13 at 03:55
  • 1
    garbage code can compile fine. You know what the debugger is for right? Debugging at run-time. – Mitch Wheat Nov 16 '13 at 03:56
  • 2
    I just told you what the main problem is, and not caring about being rude, I'll also tell you that the sooner you learn to use a debugger the better off you're going to be. N.Wirth spent half his professional career on the business end of a debugger (he freely admits this), and he has quite literally one of the most brilliant minds in CS *history*, so don't think it can escape you for long. – WhozCraig Nov 16 '13 at 03:56

2 Answers2

5

This is not the answer to your coding woes, but it is an example of what you're doing wrong. I certainly won't expect this to garner much attention (besides maybe a few down votes and some sharp criticisms).

C is a pass-by-value language. Though not easily grasped by most that experience it, this includes everything, (arrays not withstanding, but even those are if you apply the term "value" correctly).

Example #1: Value Parameters

This trivial example is to demonstrate that the address of the passed parameters to a function are not the same as the address of the arguments supplied to the function.

#include <stdio.h>

int foo_one(int a, int b)
{
    printf("foo:  &a = %p, &b=%p\n", &a, &b);
    return a+b;
}

int main()
{
    int a = 1, b = 2;
    printf("main: &a = %p, &b=%p\n", &a, &b);
    foo_one(a,b);
    return 0;
}

Output (address values will vary on your system)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908

Note the logical address of the variables in the function are different than those in main(). The values of a and b are pushed into temporary storage (commonly a "stack", but you likely don't know what that is without a formal data-structures course, and if you had one of those under your belt you probably would not be asking this question). Then the function call is made.


Example #2: Dysfunctional Out-Parameter

So why do you care. Well, now consider this:

#include <stdio.h>

void foo_two(int a, int b, int c)
{
    printf("foo:  &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    c = a + b;
}

int main()
{
    int a = 1, b = 2, c = 0;
    printf("main: &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    foo_two(a,b,c);
    printf("c = %d\n", c);
    return 0;
}

Output (address values will vary on your system)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934, &c=0x7fff5fbff930
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908, &c=0x7fff5fbff904
c = 0

What just happened? The c variable we modified in foo_two() was not the variable in main(). They have different memory addresses. The one we modified in foo_two() was a by-value copy (a "temp" variable discussed in Example #1).


Example #3: Functional Out-Parameter

If only there was a way we could tell foo_three() the memory address of the variable in main() directly... Somehow pass that address as the "value" for the parameter, then use it to store our result where it needs to go; in main::c.

This is exactly what pointers do. In C, a pointer is a variable that holds an address to some other data of a specific type. Where an int holds an integer value, a int* holds an address where an int can be found.

#include <stdio.h>

void foo_three(int a, int b, int* ptr)
{
    printf("foo:  &a = %p, &b=%p, ptr=%p\n", &a, &b, ptr);
    *ptr = a + b; // note the dereference operator
}

int main()
{
    int a = 1, b = 2, c = 0;
    printf("main: &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    foo_three(a,b,&c); // note the address of c being passed
    printf("c = %d\n", c);
    return 0;
}

Output (address values will vary on your system)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934, &c=0x7fff5fbff930
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908, ptr=0x7fff5fbff930
c = 3

This is important. Look carefully at what is being printed in foo_three(). The value of the ptr parameter, a pointer, is the same as the address of the c variable in main() this gives us the ability to modify the int at that address directly.


Summary

If you want to pass something by address in C, then passing the address is exactly what you have to do; pass the address and declare the parameter to be a pointer to the variable type. Use the dereference operator to write/read data to/from said address while in the function, and the caller-side variable will be appropriately modified.

Now after all that, look back at your program and see if you can understand how this can be applied to your problem(s). And study C pointers. They're not magic, and they are heavily used in most C programs. It's worth the time to learn as soon as possible.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
2

I presume you're a student. When learning a new language, it really helps to read other people's code. I rewrote your mean / standard deviation function, showing how I approach this kind of thing. (1-dimensional not 2-dimensional... no free lunch!)

Hope this gets you on the right track.

I do agree with the other posters that you need to get comfortable using the debugger... even if there are no compiler errors or linker errors, the program still may not work correctly. You can validate the correctness of a function by using a unit test framework such as Google Test or CppUnit, or you can just use an ad hoc test function as I show below.

// tested with minGW_w32 gcc-4.7.2

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

/// Calculate mean and standard deviation of a 1-dimensional array.
/// Example showing how to pass values by reference.
///
/// @param[in] x = 1-dimensional array of values to evaluate
/// @param[in] length = number of elements in array
/// @param[out] pdMean = caller-allocated storage for arithmetic mean average
/// @param[out] pdStdDev = caller-allocated storage for standard deviation
///
/// void return type because this function does not have a return value.
///
void calculateMeanAndStdDev (double x[], size_t length, double* pdStdDev, double* pdMean)
{
    size_t index;       // size_t is an unsigned integer type useful for counting array elements

    double sumX = 0;
    double sumXSquared = 0;
    for (index = 0; index < length; index++)
    {
        // accumulate sum of the x values
        sumX += x[index];

        // accumulate the sum of each x squared
        sumXSquared += ( x[index] * x[index] );
    }

    // pdMean is a pointer to the variable in the caller, which will receive the value
    // *pdMean is the object that double& pdMean points to.
    // I'm using the pd prefix to mean pointer to double.
    // I prefer to write this as (*pdMean) to help clarify that I'm using * to dereference a pointer, not to perform multiplication.
    (*pdMean) = sumX / length;

    double variance = 0;
    for (index = 0; index < length; index++)
    {
        const double differenceFromMean = x[index] - (*pdMean);
        // without the parenthesis this is written as  differenceFromMean = x[index] - *pdMean;

        variance += differenceFromMean * differenceFromMean;
    }
    (*pdStdDev) = sqrt ( variance / length);

    /// @note there's a more effient way to calculate mean and standard deviation, where you accumulate sumX and sumXSquared in a single pass,
    /// then mean is sumX / length and StdDev is calculated from sumXsquared and (sumX)*(sumX).
    /// For purposes of this exercise I stuck with the more direct equation.
}

/// Example ad hoc test driver calling calculateMeanAndStdDev()
void Test_calculateMeanAndStdDev()
{
    double demoArray[] = { 1.0, 2.0, 3.0, 7.5, 9.2 };
    const double expect_Mean = 4.54;
    const double expect_StdDev = 3.2196894260161177;

    double Mean; // will be filled in by calculateMeanAndStdDev
    double StdDev; // will be filled in by calculateMeanAndStdDev
    calculateMeanAndStdDev(demoArray, sizeof(demoArray)/sizeof(double), &StdDev, &Mean);

    const double compare_threshold = 0.001;
    if ( abs(Mean - expect_Mean) > compare_threshold ) {
        printf("\n""Test_calculateMeanAndStdDev() fail: Mean=%1.6f buf expect_Mean=%1.6f", Mean, expect_Mean);
    } else {
        printf("\n""Test_calculateMeanAndStdDev(): Mean=%1.6f as expected", Mean);
    }
    if ( abs(StdDev - expect_StdDev) > compare_threshold ) {
        printf("\n""Test_calculateMeanAndStdDev() fail: StdDev=%1.6f buf expect_StdDev=%1.6f", StdDev, expect_StdDev);
    } else {
        printf("\n""Test_calculateMeanAndStdDev(): StdDev=%1.6f as expected", StdDev);
    }
}

int main(void)
{
    Test_calculateMeanAndStdDev();
    return 0;
}

C pointers are very powerful and fundamental to the language, but they're also one of the trickiest features to understand. That's why languages like Java hide this pointer mechanism from the programmer. In C you have to program defensively, because the compiler always assumes you know what you're doing. Want to write code that modifies itself during execution? C is ok with that, even if your program kills itself. Write outside the bounds of an array allocated on the stack? Sure, no problem, your function just won't be able to return... So all in all, when dealing with pointers, especially when first starting out, code defensively to try to avoid getting confused. Because you can't rely on compiler warnings to tell you if there's going to be a problem.

MarkU
  • 359
  • 2
  • 10