using function to find max value in an array - c

Can someone please explain what I'm doing wrong. I need to use an array to find the max value of the percentages array and display that amount and the year in the corresponding years array.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int findHighNumber (double percentages[], int elements);
int main (void)
{
int index;
int elements;
int years[] = {2000, 2002, 2004, 2006, 2008, 2010, 2012};
double percentages[] = {6.7, 6.6, 8, 9, 11.3, 14.7, 14.6};
int sampleSizes[] = {187761, 444050, 172335, 308038, 337093, 1000, 346978};
int high = findHighNumber(percentages, elements);
printf ("%i had the highest percentage with autism at %.2lf%%.\n", years[high], percentages[high]);
return 0;
}
int findHighNumber (double percentages[], int elements)
{
int index, high;
high = percentages[0];
for (index = 1; index < elements; index++)
if (high < percentages[index])
{
high = percentages[index];
}
return high;
}

First, you have to declare the elements variable in main():
int elements = 7;
or even better:
int elements = sizeof(percentages) / sizeof(*percentages);
which computes the array size automatically.
Then, don't modify the elements variable in you loop.
If you do it, each time the current maximum is changed, you program your loop to stop after the next element, potentially missing the real maximum which can be located at the end of the array.
Then, like Bob said, you should return the index of the maximum, this way, you can retrieve the corresponding sampleSize, or year.
When you do years[high], you're using a percentage as an array index which can take any real value in [0,100], instead of an index which must stay in {0, 1, 2, 3, 4, 5, 6}.
What's more, you store high in an integer variable, resulting in a truncation of it's value. You may prefer to store it as a double variable.
So findHighNumber() can become:
int findHighNumber(double percentages[], int elements)
{
int index;
double high;
int high_index;
high_index = 0;
high = percentages[high_index];
for (index = 1; index < elements; index++)
if (high < percentages[index]) {
high = percentages[index];
high_index = index;
}
return high_index;
}
The main() function now can become something like:
int main (void)
{
int years[] = {2000, 2002, 2004, 2006, 2008, 2010, 2012};
double percentages[] = {6.7, 6.6, 8, 9, 11.3, 14.7, 14.6};
int sampleSizes[] = {187761, 444050, 172335, 308038, 337093, 1000,
46978};
int elements = sizeof(percentages) / sizeof(*percentages);
int high_index = findHighNumber(percentages, elements);
printf ("%i had the highest percentage with autism at %.2lf%% (sample"
"size was %d).\n", years[high_index], percentages[high_index],
sampleSizes[high_index]);
return 0;
}
Then, some small advices:
putting a prototype of findHighNumber() is not needed, just define the function above the places where it's needed. This way, when you really have to put a prototype for a function, it a hint saying that you were forced to do so, (for example for mutually recursive functions), plus it shortens the code.
you should define a, for example, struct autism_sample like that:
struct autism_sample {
int year;
int sample_size;
double percentage;
};
This way, you just have to define one array:
struct autism_sample autism_samples[] = {
{
.year = 2000,
.sample_size = 187761,
.percentage = 6.7,
},
{
.year = 2002,
.sample_size = 444050,
.percentage = 6.6,
},
...
};
This way, your data is organized in a more logical way, less error-prone to maintain and you gain the choice, in the implementation of findHighNumber(), to return either the index of the maximum or directly, a pointer to the element holding the maximum, the index becomes then useless.
What's more, it's easier to (un)serialize...

I'm not sure if this is a typo here, but it appears while calling
int high = findHighNumber(percentages, elements);
you don't have a variable elements defined there. That said, you have another syntax error (missing the closing }) near
if (high < percentages[index])
{
high = percentages[index]; ///after this.
Finally, inside findHighNumber (), elements is local to the function, so, the only usage as elements = index+1; is useless.

Given the way you are storing and using data, you should return the index where the higher element is, not its value.
Also you have to pass the right size of the array (and don't change it inside the function), while you are passing an uninitialized value.

You should send the index instead of the value.
int findIndexOfMax (double percentages[], int elements) {
int index = 0;
int highIndex = 0;
double high = 0.0;
high = percentages[highIndex];
for (index = 1; index < elements; index++)
{
if (high < percentages[index])
{
high = percentages[index];
highIndex = index;
}
}
return highIndex;
}

You are returning the wrong value .. you should not return what's the highest value but you should return the index of it.
or you you can simply print the result that you want in the function you're calling.
Also, I don't see that you have initialized the variable elements.

Related

How to retrieve closest value to mean and its location C

I was just wondering how you would get the closest value to the mean, the program retrieves input from the user and then outputs a 2D array, within the two ranges the user inputted. It then also outputs lowest and highest array values, the mean(all of this has been coded), I'm just unsure how to write a function to return the closest value in the array to the mean and then the location within the array.
Subtract the mean value from each element.
Take the absolute value of the result.
Store the position and element which have lowest difference.
int fnFindClosestVal(int arn2DArray[][6], int nRows, int nCols, double nTotal, int *posRow, int *posCol)
{
int nClosestValue = arn2DArray[0][0];
int nDiff = abs(arn2DArray[0][0] - nTotal);
int Row,Col;
for (nCountRows = 0; nCountRows < nRows; nCountRows++)
{
for (nCountCols = 0; nCountCols < nCols; nCountCols++)
{
if(abs(arn2DArray[nCountRows][nCountCols] - nTotal) < nDiff)
{
nDiff = abs(arn2DArray[nCountRows][nCountCols] - nTotal);
nClosestValue = arn2DArray[nCountRows][nCountCols];
*posRow = nCountRows;
*posCol = nCountCols;
}
}
}
return nClosestValue;
}

Need help understanding logic of function

monthly->maxTemperature = yearData[i].high;
monthly->minTemperature = yearData[i].low;
I just can't seem to understand the logic of what the iterations will look like or how to access the proper elements in the array of data to get the proper data for each month.... without corrupting data. Thanks!
You're on the right track:
void stats(int mth, const struct Data yearData[], int size, struct Monthly* monthStats)
{
// These are used to calc averages
int highSum = 0;
int lowSum = 0;
int days = 0;
// Initialize data
monthly->maxTemperature = INT_MIN;
monthly->minTemperature = INT_MAX;
monthly->totalPrecip = 0;
for (int i = 0; i < size; ++i) {
// Only use data from given month
if (yearData[i].month == mth) {
days += 1;
if (yearData[i].high > monthly->maxTemperature) monthly->maxTemperature = yearData[i].high;
if (yearData[i].low < monthly->minTemperature) monthly->minTemperature = yearData[i].low;
highSum += yearData[i].high;
lowSum + yearData[i].low;
monthly->totalPrecip += yearData[i].precip;
}
}
if (0 != days) {
monthly->avgHigh = highSum / days;
monthly->avgLow = lowSum / days;
}
}
Before working on the assignment it's a good idea to examine the API that you need to implement for clues. First thing to notice is that the reason the struct Monthly is passed to your function by pointer is so that you could set the result into it. This is different from the reason for passing struct Data as a pointer*, which is to pass an array using the only mechanism for passing arrays available in C. const qualifier is a strong indication that you must not be trying to modify anything off of the yearData, only the monthStats.
This tells you what to do with the min, max, average, and total that you are going to find in your function: these need to be assigned to fields of monthStats, like this:
monthStats->maxTemperature = maxTemperature;
monthStats->minTemperature = minTemperature;
...
where maxTemperature, minTemperature, and so on are local variables that you declare before entering the for loop.
As far as the for loop goes, your problem is that you ignore the mth variable completely. You need to use its value to decide if an element of yearData should be considered for your computations or not. The simplest way is to add an if to your for loop:
int maxTemperature = INT_MIN; // you need to include <limits.h>
int minTemperature = INT_MAX; // to get definitions of INT_MIN and INT_MAX
for(int i = 0; i<size; ++i) {
if (yearData[i].month < mth) continue;
if (yearData[i].month > mth) break;
... // Do your computations here
}
* Even though it looks like an array, it is still passed as a pointer

Why does the value of a pointer change after passing it to a function that does not modify the pointer?

The pointer in main(), ptrTop, is initialized to point to int topDeck = 1. Every time I run the program, the value of the (I think) dereferenced pointer changes to a different number. I believe that the problem lies in the deal() function. If I comment out the call to deal() in main(), the value of my pointer is not modified. I did not write any statements that change the value of the pointer. I wrote comments around the parts of the code that might be relevant to the question.
/*
* This is a card dealing program.
* the fucntion deal() keeps changing the value of
* the int pointer ptrTop declared in main(). sometimes,
* the value is what it is sopposed to be (1), but when i run
* the program again, it is a different value. I used
* gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
*/
int main(void) {
int topDeck = 1;
int *ptrTop = &topDeck;
//this ptrTop is sopposed to keep track of the last
//card dealt, but it randomly changes every time I run
unsigned int handSuit[5] = {0};
unsigned int handFace[5] = {0};
unsigned int deck[SUITS][FACES] = {0};
deal(deck, face, suit, ptrTop, handSuit, handFace);
printf("%i\n", *ptrTop);
// If print the value while I comment out the deal() in line 55,
// the value of * ptrTop does not change.
// this gives me reason to believe that deal() is causing the trouble.
}
void deal(unsigned int wDeck[][FACES], const char *wFace[], const char *wSuit[],
int *ptrTop, unsigned int handSuit[], unsigned int handFace[])
{
size_t card;
size_t row;
size_t column;
int top = *ptrTop;
// i have to use top because if i don't the dea() function will print
// more than 5 cards (it is sopposed to print a 5 card hand.
// these for loops loop through the double scripted array wDeck
for (card = top; card <= top + 4; ++card) {
for (row = 0; row < SUITS; ++row) {
for(column = 0; column < FACES; ++column) {
if(wDeck[row][column] == card) {
printf( "%s of %s \n", wFace[ column ], wSuit[ row ]);
handFace[card] = column;
handSuit[card] = row;
}
}
}
}
// *ptrTop = card;
// the value of *ptrTop consistently becomes six if line above is uncommented.
// I would think that the value should still be 1
// when the program is run in this state.
}
This obscure loop is the cause:
for (card = top; card <= top + 4; ++card)
Card gets an index from 1 to 5, while you have variables
unsigned int handSuit[5] = {0};
unsigned int handFace[5] = {0};
That only supports index 0 to 4. You access these arrays out-of-bounds, and as a side effect of that undefined behavior, you overwrite other variables.
I'm not really sure what other value (than six) of *ptrTop you expect; let's take a look at deal:
for (card = top; card <= top + 4; ++card)
and remember, this is the value of top, as initialized in main:
int topDeck = 1;
int *ptrTop = &topDeck;
So, in deal, you loop five times, incrementing card, then in the last iteration the for loop will increment card for the fifth time, see that it is 6, and since 6 <= 5 is false, it will quit, then if you do *ptrTop = card;, *ptrTop is indeed consistently equal to six.

Max in array and its frequency

How do you write a function that finds max value in an array as well as the number of times the value appears in the array?
We have to use recursion to solve this problem.
So far i am thinking it should be something like this:
int findMax(int[] a, int head, int last)
{
int max = 0;
if (head == last) {
return a[head];
}
else if (a[head] < a[last]) {
count ++;
return findMax(a, head + 1, last);
}
}
i am not sure if this will return the absolute highest value though, and im not exactly sure how to change what i have
Setting the initial value of max to INT_MIN solves a number of issues. #Rerito
But the approach OP uses iterates through each member of the array and incurs a recursive call for each element. So if the array had 1000 int there would be about 1000 nested calls.
A divide and conquer approach:
If the array length is 0 or 1, handle it. Else find the max answer from the 1st and second halves. Combine the results as appropriate. By dividing by 2, the stack depth usage for a 1000 element array will not exceed 10 nested calls.
Note: In either approach, the number of calls is the same. The difference lies in the maximum degree of nesting. Using recursion where a simple for() loop would suffice is questionable. To conquer a more complex assessment is recursion's strength, hence this approach.
To find the max and its frequency using O(log2(length)) stack depth usage:
#include <stddef.h>
typedef struct {
int value;
size_t frequency; // `size_t` better to use that `int` for large arrays.
} value_freq;
value_freq findMax(const int *a, size_t length) {
value_freq vf;
if (length <= 1) {
if (length == 0) {
vf.value = INT_MIN; // Degenerate value if the array was size 0.
vf.frequency = 0;
} else {
vf.value = *a;
vf.frequency = 1;
}
} else {
size_t length1sthalf = length / 2;
vf = findMax(a, length1sthalf);
value_freq vf1 = findMax(&a[length1sthalf], length - length1sthalf);
if (vf1.value > vf.value)
return vf1;
if (vf.value == vf1.value)
vf.frequency += vf1.frequency;
}
return vf;
}
Your are not thaaaat far.
In order to save the frequency and the max you can keep a pointer to a structure, then just pass the pointer to the start of your array, the length you want to go through, and a pointer to this struct.
Keep in mind that you should use INT_MIN in limits.h as your initial max (see reset(maxfreq *) in the code below), as int can carry negative values.
The following code does the job recursively:
#include <limits.h>
typedef struct {
int max;
int freq;
} maxfreq;
void reset(maxfreq *mfreq){
mfreq->max = INT_MIN;
mfreq->freq = 0;
}
void findMax(int* a, int length, maxfreq *mfreq){
if(length>0){
if(*a == mfreq->max)
mfreq->freq++;
else if(*a > mfreq->max){
mfreq->freq = 1;
mfreq->max = *a;
}
findMax(a+1, length - 1, mfreq);
}
}
A call to findMax will recall itself as many times as the initial length plus one, each time incrementing the provided pointer and processing the corresponding element, so this is basically just going through all of the elements in a once, and no weird splitting.
this works fine with me :
#include <stdio.h>
#include <string.h>
// define a struct that contains the (max, freq) information
struct arrInfo
{
int max;
int count;
};
struct arrInfo maxArr(int * arr, int max, int size, int count)
{
int maxF;
struct arrInfo myArr;
if(size == 0) // to return from recursion we check the size left
{
myArr.max = max; // prepare the struct to output
myArr.count = count;
return(myArr);
}
if(*arr > max) // new maximum found
{
maxF = *arr; // update the max
count = 1; // initialize the frequency
}
else if (*arr == max) // same max encountered another time
{
maxF = max; // keep track of same max
count ++; // increase frequency
}
else // nothing changes
maxF = max; // keep track of max
arr++; // move the pointer to next element
size --; // decrease size by 1
return(maxArr(arr, maxF, size, count)); // recursion
}
int main()
{
struct arrInfo info; // return of the recursive function
// define an array
int arr[] = {8, 4, 8, 3, 7};
info = maxArr(arr, 0, 5, 1); // call with max=0 size=5 freq=1
printf("max = %d count = %d\n", info.max, info.count);
return 0;
}
when ran, it outputs :
max = 8 count = 3
Notice
In my code example I assumed the numbers to be positive (initializing max to 0), I don't know your requirements but you can elaborate.
The reqirements in your assignment are at least questionable. Just for reference, here is how this should be done in real code (to solve your assignment, refer to the other answers):
int findMax(int length, int* array, int* maxCount) {
int trash;
if(!maxCount) maxCount = &trash; //make sure we ignore it when a NULL pointer is passed in
*maxCount = 0;
int result = INT_MIN;
for(int i = 0; i < length; i++) {
if(array[i] > result) {
*maxCount = 1;
result = array[i];
} else if(array[i] == result) {
(*maxCount)++;
}
}
return result;
}
Always do things as straight forward as you can.

How to find which value is closest to a number in C?

I have the following code in C:
#define CONST 1200
int a = 900;
int b = 1050;
int c = 1400;
if (A_CLOSEST_TO_CONST) {
// do something
}
What is a convenient way to check whether if a is the closest value to CONST among a,b and c ?
Edit:
It doesn't matter if I have 3 variables or an array like this (it could be more than 3 elements):
int values[3] = {900, 1050, 1400};
This works for three variables:
if (abs(a - CONST) <= abs(b - CONST) && abs(a - CONST) <= abs(c - CONST)) {
// a is the closest
}
This works with an array of one or more elements, where n is the number of elements:
int is_first_closest(int values[], int n) {
int dist = abs(values[0] - CONST);
for (int i = 1; i < n; ++i) {
if (abs(values[i] - CONST) < dist) {
return 0;
}
}
return 1;
}
See it working online: ideone
Compare the absolute value of (a-CONST), (b-CONST) and (c-CONST). Whichever absolute value is lowest, that one is closest.
Here is a generalized method. The min_element() function takes an int array, array size, and pointer to a comparison function. The comparison predicate returns true if the first values is less than the second value. A function that just returned a < b would find the smallest element in the array. The pinouchon() comparison predicate performs your closeness comparison.
#include <stdio.h>
#include <stdlib.h>
#define CONST 1200
int pinouchon(int a, int b)
{
return abs(a - CONST) < abs(b - CONST);
}
int min_element(const int *arr, int size, int(*pred)(int, int))
{
int i, found = arr[0];
for (i = 1; i < size; ++i)
{
if (pred(arr[i], found)) found = arr[i];
}
return found;
}
int main()
{
int values[3] = {900, 1050, 1400};
printf("%d\n", min_element(values, 3, pinouchon));
return 0;
}
I m adding something in Mark Byres code.....
int is_first_closest(int values[]) {
int dist = abs(values[0] - CONST),closest; //calculaing first difference
int size = sizeof( values ) //calculating the size of array
for (int i = 1; i < size; ++i) {
if (abs(values[i] - CONST) < dist) { //checking for closest value
dist=abs(values[i] - CONST); //saving closest value in dist
closest=i; //saving the position of the closest value
}
}
return values[i];
}
This function will take an array of integers and return the number which is closest to the CONST.
You need to compare your constant to every element. (works well for 3 elements but it's a very bad solution for bigger elementcount, in which case i suggest using some sort of divide and conquer method). After you compare it, take their differences, the lowest difference is the one that the const is closest to)
This answer is a reaction to your edit of the original question and your comment.
(Notice that to determine the end of array we could use different approaches, the one i shall use in this particular scenario is the simplest one.)
// I think you need to include math.h for abs() or just implement it yourself.
// The code doesn't deal with duplicates.
// Haven't tried it so there might be a bug lurking somewhere in it.
const int ArraySize = <your array size>;
const int YourConstant = <your constant>;
int values[ArraySize] = { ... <your numbers> ... };
int tempMinimum = abs(YourArray[0] - YourConstant); // The simplest way
for (int i = 1; i < ArraySize; i++) { // Begin with iteration i = 1 since you have your 0th difference computed already.
if (abs(YourArray[i] - YourConstant) < tempMinumum) {
tempMinumum = abs(YourArray[i] - YourConstant);
}
}
// Crude linear approach, not the most efficient.
For a large sorted set, you should be able to use a binary search to find the two numbers which (modulo edge cases) border the number, one of those has to be the closest.
So you would be able to achieve O(Log n) performance instead of O(n).
pseudocode:
closest_value := NULL
closest_distance := MAX_NUMBER
for(value_in_list)
distance := abs(value_in_list - CONST)
if (distance < closest_distance)
closest_value := value_in_list
closest_distance := distance
print closest_value, closest_distance

Resources