Mean function using values from double array displaying wrong values - c

Very new to C, anyways been coding a program where you enter pairs of doubles which are stored in separate arrays. I have created a function to get the mean of the numbers but when I call it inside main the values are different. Any ideas?
MEAN FUNCTION:
mean(double *arr)
{
double sum = 0.0;
double meanValue = 0.0;
int i;
for (i = 0; i < arr[i]; i++)
{
sum += arr[i];
meanValue = sum / i;
}
printf("\nmean: %.3lf", meanValue);
}
MAIN:
double num1[1001];
mean(num1);
And, I am getting the num1 and num2 values using:
for (k = 0; (scanf_s("%lf,%lf", &num1[k], &num2[k] ) == 2); k++)

The function needs to know how many of the array elements it should process.
mean(double *arr, int size)
{
double sum = 0.0;
double meanValue = 0.0;
int i;
for (i = 0; i < size; i++)
{
sum += arr[i];
}
meanValue = size > 0 ? sum / size : 0;
printf("\nmean: %.3lf", meanValue);
}
The size is the value of k after the input loop is done, so you call it:
mean(num1, k);

Your function needs to pieces of information:
the pointer to the data array;
the size of the array (number of elements).
However, the way you are computing the mean is subjected to bad numeric conditioning (floating point overflow). Here I suggest using the Incremental Averaging instead. Please consider this code:
double mean(double *arr, int num)
{
double res = arr[0];
for (int i = 1; i < num; ++i)
res += (arr[i] - res) / (i+1.0);
return res;
}
Note that I'm assuming you are using a C99 compliant compiler for the integer declaration inside the for loop.

Related

How to handle unknown type of numbers in C? [duplicate]

This question already has answers here:
How to achieve function overloading in C?
(14 answers)
Create a C function that accepts parameters of different data types
(6 answers)
Closed 5 years ago.
I need to write a method to calculate the average of an unknown type of numbers (double, float, int...). I tried to do something like this, but it works for double type only:
double average(void *arr, int length, int bytes) {
int i;
double sum = 0;
double num;
for (i = 0; i < length; i++) {
memcpy(&num, (char *) arr, bytes);
sum += num;
arr = (char *) arr + bytes;
}
return sum / length;
}
Any suggestions?
You can't sum the array values if you don't know what type they are. Relying on the bytes parameter alone is not enough, since int and float are commonly the same size in many compilers, but they are very different types. You lose type information when operating with void*.
If you must use void*, the only way to solve this is to pass in a parameter that specifies what type the array actually holds, and then cast the void* accordingly.
I suggest writing a separate function for each type, eg:
enum dataType {dtInt, dtFloat, dtDouble};
double averageInt(int *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum / length;
}
double averageFloat(float *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum / length;
}
double averageDouble(double *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum / length;
}
double average(void *arr, int length, enum dataType arrType)
{
switch (arrType)
{
case dtInt: return averageInt((int*)arr, length);
case dtFloat: return averageFloat((float*)arr, length);
case dtDouble: return averageDouble((double*)arr, length);
}
return 0;
}
Alternatively:
enum dataType {dtInt, dtFloat, dtDouble};
double sumInt(int *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum;
}
double sumFloat(float *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum;
}
double sumDouble(double *arr, int length)
{
double sum = 0;
for (int i = 0; i < length; ++i)
sum += arr[i];
return sum;
}
double average(void *arr, int length, enum dataType arrType)
{
double sum;
switch (arrType)
{
case dtInt: sum = sumInt((int*)arr, length); break;
case dtFloat: sum = sumFloat((float*)arr, length); break;
case dtDouble: sum = sumDouble((double*)arr, length); break;
default: sum = 0; break;
}
return sum / length;
}

Code Bug: Segmentation Fault [EVERYTIME]

I am writing this C/C++ program that is suppose to find the mean, median, and mode of a varied size array. Although, I keep getting a Segmentation Fault regardless of the input. What is wrong with my code? Any suggestions always appreciated! :)
Here is the code:
#include <stdio.h>
//#include <string.h>
//#include <math.h>
#include <stdlib.h>
Prototypes:
void sort(double*[],int);
static int min(double,double[],int);
double mean(double[],int);
double median(double[],int);
double mode(double[],int);
int numberOf(double,double[],int);
Main Function:
int main() {
int i;
scanf(" %d ",&i); //10
double arr[i]; //array that contains all the values and will be sortted
for (int j=0; j<i; j++) { //64630 11735 14216 99233 14470 4978 73429 38120 51135 67060
scanf(" %lf ",&arr[j]);
}
printf("%.1lf\n%.1lf\n%.0lf",mean(arr,i),median(arr,i),mode(arr,i));
return 0;
}
Sort Function:
The end result should update the array arr from the call in the Median Function. Changes the used values in the original array to -1 until that is the entire array.
void sort(double* arr[],int l) {
double arr2[l];
for (int i=0; i<l; i++) {
int j;
if (i)
j = min(arr2[i-1], *arr, l);
else
j = min(0, *arr, l);
arr2[i] = *arr[j];
*arr[j] = -1;
}
for (int i=0; i<l; i++) {
*arr[i] = arr2[i];
}
}
Min Function (helper function for the Sort Function):
Finds the minimum value amongst the array elements that is greater than or equal to minLookingTo
Returns the position the value is in.
static int min(double minLookingTo,double arr[],int l) {
int minP;
double minA = minLookingTo;
for (int i=0; i<l; i++) {
if (arr[i] == -1)
continue;
if (minLookingTo<=arr[i] && arr[i]<=minA) {
minP = i;
minA = arr[i];
}
}
return minP;
}
Mean Function:
Returns the mean of the inputted array with the length l
double mean(double arr[],int l){
double total = 0;
for (int i=0; i<l; i++) {
total += arr[i];
}
return total/l;
}
Median Function:
Uses the Sort Function. Assuming that works, returns the median.
double median(double arr[],int l){
sort(&arr,l);
double d = arr[(l/2)+1];
double dd = arr[(l/2)];
if (l%2!=0)
return d;
return (d+dd)/2;
}
Mode Function:
Uses the NumberOf Function to determine the array element with the maximum amount of repeats. Returns the lowest value of the highest (equal) repeats.
double mode(double arr[],int l){
int maxA;
int maxP;
for (int i=0;i<l;i++) {
int j = numberOf(arr[i],arr,l);
if (j>maxA) {
maxA = j;
maxP = i;
}
else if (j==maxA && arr[maxP]>arr[i])
maxP = i;
}
double d = arr[maxP];
return d;
}
NumberOf Function:
Helper function for the Mode Function. Returns the amount of elements with the looking value.
int numberOf(double looking,double arr[],int l) {
int amount = 0;
for (int i=0; i<l; i++)
if (looking == arr[i])
amount++;
return amount;
}
I tracked your segmentation fault to your sort() routine called by median(). Rather than fix sort(), I substituted qsort() from the library to convince myself that's the problem:
// Median Function:
// Uses the Sort Function. Assuming that works, returns the median.
int comparator(const void *p, const void *q) {
double a = *((double *) p);
double b = *((double *) q);
return (a > b) - (a < b); // compare idiom
}
double median(double array[], int length) {
// sort(array, length);
qsort(array, length, sizeof(double), &comparator);
double d = array[length / 2];
if (length % 2 != 0) {
return d;
}
double dd = array[(length / 2) - 1];
return (d + dd) / 2;
}
For the example list of numbers provided, after correcting the rest of the code, this returns a median of 44627.5
Other fixes:
You're missing a final newline here:
printf("%.1lf\n%.1lf\n%.0lf",mean(arr,i),median(arr,i),mode(arr,i));
You should probably initialize the variables in mode():
double mode(double array[], int length) {
int maxA = INT_MIN;
int maxP = -1;
for (int i = 0; i < length; i++) {
int j = numberOf(array[i], array, length);
if (j > maxA) {
maxA = j;
maxP = i;
} else if (j == maxA && array[maxP] > array[i]) {
maxP = i;
}
}
return array[maxP];
}
Your code has a series of errors. Some of them:
You don´t need (in this case) to use spaces in scanf. This is causing a reading error.
You don't need to pass an array address to a function in order to alter its values. Arrays are always passed by reference. So change your function from void sort(double*[],int); to void sort(double[],int);, make the necessary corrections inside the function and call it using sort(arr,l); instead of sort(&arr,l);
Your min() function declares an uninitialized variable minP, so this variable contains garbage from your memory. The for() loop isn't entering none of the both if() conditions, so your function ends and returns the still uninitialized variable minP. This random value is then used to access an index in your array: j = min(0, arr, l); min returns an random number and then arr2[i] = arr[j]; accessing forbidden memory region, which is causing your segmentation fault error. The same problem is occurring with the variables maxP and maxA in the mode() function.
You must always be careful when accessing your arrays to not go beyond its bounds and always be sure that variables will be initialized when using them. And as others have commented, I also highly recommend you to learn how to debug your programs, since this will help you to analyze its execution and trace bugs.

Excel / C - get input with array*

I'm working on a simple XLL addin and trying to get the input with a regular double* (not FP or OPER) because from what I understand, Excel should work with regular C data types. I can't get it to work, after many modifications, now it only returns the value in my last cell. What am I doing wrong?\
static AddIn xai_array_try(
"?xll_array_try", XLL_DOUBLE XLL_DOUBLE_,
"ARRAY.TRY", "Array",
"STL", "Test Sum Array."
);
double WINAPI xll_array_try(const double *arr) {
#pragma XLLEXPORT
int i;
double sum = 0;
int size = 3;
for (i = 0; i < size; ++i) {
sum += arr[i];
}
return sum;
}
If I would get it as a FP or OPER, would I be able then to pass it to a function that takes input as array?
figured it out according to this
my addin output was wrong, and my function input was wrong.
static AddIn xai_array_try(
"?xll_array_try", XLL_DOUBLE "O%",
"ARRAY.TRY", "Array",
"STL", "Test Sum Array."
);
double WINAPI xll_array_try(int *rows, int *columns, double *arr) {
#pragma XLLEXPORT
int i;
double sum = 0;
int size = *rows * *columns;
for (i = 0; i < size; ++i) {
sum += arr[i];
}
return sum;
}

Knapsack algorithm for large input

I have developed this knapsack algorithm based on pseudo-code found on wikipedia. It works fine for small number of items and capacity (n=6, v=2014), but it crashes for large numbers (n=5, v=123456789).
Additional problem is, that my program is tested by makefile with time limit set at 1 second.
What can i do to save time and memory?
v - Knapsack capacity
n - Number of items
weight[] - Weights
value[] - Values
int knapSack(int v, int weight[], int value[], int n){
int a, i, j;
int **ks;
ks = (int **)calloc(n+1, sizeof(int*));
for(a = 0; a < (n+1); a++) {
ks[a] = (int *)calloc(v+1, sizeof(int));
}
for (i = 1; i <= n; i++){
for (j = 0; j <= v; j++){
if (weight[i-1] <= j){
ks[i][j] = max(value[i-1] + ks[i-1][j-weight[i-1]], ks[i-1][j]);
} else {
ks[i][j] = ks[i-1][j];
}
}
}
int result = ks[n][v];
for(i = 0; i < (n+1); i++) {
free(ks[i]);
}
free(ks);
return result;
}
An array of 123456789 integer elements declared on the stack will crash many implementations of C. Sounds like this is your problem. Did you declare your arrays inside of a function (on the stack)?
// on heap
static int v[123456789]={0};
// on the stack (inside a function like main() )
int foo()
{
int v[123456789]={0};
}

C Allocating array of 500 and more longs

So.. I have something like this. It is supposed to create arrays with 10, 20, 50 100 .. up to 5000 random numbers that then sorts with Insertion Sort and prints out how many comparisions and swaps were done .. However, I am getting a runtime exception when I reach 200 numbers large array .. "Access violation writing location 0x00B60000." .. Sometimes I don't even reach 200 and stop right after 10 numbers. I have literally no idea.
long *arrayIn;
int *swap_count = (int*)malloc(sizeof(int)), *compare_count = (int*)malloc(sizeof(int));
compare_count = 0;
swap_count = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
compare_count = 0;
swap_count = 0;
free(arrayIn);
}
}
}
EDIT: ok with this free(arrayIn); I get this " Stack cookie instrumentation code detected a stack-based buffer overrun." and I get nowhere. However without it it's "just" "Access violation writing location 0x00780000." but i get up to 200numbers eventually
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
arr[i] = (RAND_MAX + 1)*rand() + rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
I am sure your compiler told you what was wrong.
You are passing a long** to a function that expects a int* at the line
fill_array(&arrayIn, n);
function prototype is
void fill_array(int *arr, int n)
Same problem with the other function. From there, anything can happen.
Always, ALWAYS heed the warnings your compiler gives you.
MAJOR EDIT
First - yes, the name of an array is already a pointer.
Second - declare a function prototype at the start of your code; then the compiler will throw you helpful messages which will help you catch these
Third - if you want to pass the address of a simple variable to a function, there is no need for a malloc; just use the address of the variable.
Fourth - the rand() function returns an integer between 0 and RAND_MAX. The code
a[i] = (RAND_MAX + 1) * rand() + rand();
is a roundabout way of getting
a[i] = rand();
since (RAND_MAX + 1) will overflow and give you zero... If you actually wanted to be able to get a "really big" random number, you would have to do the following:
1) make sure a is a long * (with the correct prototypes etc)
2) convert the numbers before adding / multiplying:
a[i] = (RAND_MAX + 1L) * rand() + rand();
might do it - or maybe you need to do some more casting to (long); I can never remember my order of precedence so I usually would do
a[i] = ((long)(RAND_MAX) + 1L) * (long)rand() + (long)rand();
to be 100% sure.
Putting these and other lessons together, here is an edited version of your code that compiles and runs (I did have to "invent" a print_array) - I have written comments where the code needed changing to work. The last point above (making long random numbers) was not taken into account in this code yet.
#include <stdio.h>
#include <stdlib.h>
// include prototypes - it helps the compiler flag errors:
void fill_array(int *arr, int n);
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count);
void print_array(int *arr, int n, int *swap_count, int *compare_count);
int main(void) {
// change data type to match function
int *arrayIn;
// instead of mallocing, use a fixed location:
int swap_count, compare_count;
// often a good idea to give your pointers a _p name:
int *swap_count_p = &swap_count;
int *compare_count_p = &compare_count;
// the pointer must not be set to zero: it's the CONTENTs that you set to zero
*compare_count_p = 0;
*swap_count_p = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count_p, compare_count_p);
print_array(arrayIn, n, swap_count_p, compare_count_p);
swap_count = 0;
compare_count = 0;
free(arrayIn);
}
}
}
return 0;
}
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
// arr[i] = (RAND_MAX + 1)*rand() + rand(); // causes integer overflow
arr[i] = rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
void print_array(int *a, int n, int* sw, int *cc) {
int ii;
for(ii = 0; ii < n; ii++) {
if(ii%20 == 0) printf("\n");
printf("%d ", a[ii]);
}
printf("\n\nThis took %d swaps and %d comparisons\n\n", *sw, *cc);
}
You are assigning the literal value 0 to some pointers. You are also mixing "pointers" with "address-of-pointers"; &swap_count gives the address of the pointer, not the address of its value.
First off, no need to malloc here:
int *swap_count = (int*)malloc(sizeof(int)) ..
Just make an integer:
int swap_coint;
Then you don't need to do
swap_coint = 0;
to this pointer (which causes your errors). Doing so on a regular int variable is, of course, just fine.
(With the above fixed, &swap_count ought to work, so don't change that as well.)
As I told in the comments, you are passing the addresses of pointers, which point to an actual value.
With the ampersand prefix (&) you are passing the address of something.
You only use this when you pass a primitive type.
E.g. filling the array by passing an int. But you are passing pointers, so no need to use ampersand.
What's actually happening is that you are looking in the address space of the pointer, not the actual value the pointer points to in the end. This causes various memory conflicts.
Remove all & where you are inputting pointers these lines:
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
So it becomes:
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count, compare_count);
print_array(arrayIn, n, swap_count, compare_count);
I also note that you alloc memory for primitive types, which could be done way simpler:
int compare_count = 0;
int swap_count = 0;
But if you choose to use the last block of code, DO use &swap_count and &compare_count since you are passing primitive types, not pointers!

Resources