C programming help - Page 1
Forum section: electronics / general

author: Cujo
author_rank: Regular Contributor
timestamp: August 14, 2020, 02:48:25 am
content: I need the array in the main function to pass it's values the the average function. But for some reason I can't figure it out. Any way to do this?#include <stdio.h>int average(float numbers);int main(void){float numbers = {0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1};float a, b;a = average(b);return(numbers);}int average(float numbers){float total = 0;float avg = 0;int i;for(i = 0; i <= 10; i++){total = total + numbers;}avg = total / 10;printf("The average is: %.1f\n", avg);return(0);}

author: greenpossum
author_rank: Frequent Contributor
timestamp: August 14, 2020, 03:17:10 am
content: 1. You're not passing the array to average, you are passing b. And main should not be returning numbers.2. numbers in average should be declared as float * or float [], and you have to refer to the elements as numbers.3. There's no need for average to be an int function if if always returns 0. It could be a void function.

author: ledtester
author_rank: Super Contributor
timestamp: August 14, 2020, 03:49:37 am
content: https://www.tutorialspoint.com/cprogramming/c_passing_arrays_to_functions.htmExample even uses an average computing function!

author: fanOfeeDIY
author_rank: Unknown
timestamp: August 14, 2020, 04:59:34 am
content: This is like a homework from a class or so.This is how I would do if it is for minimum changes.Code:#include <stdio.h>#include <stdlib.h>#define MAX_N 10float average(float *numbers){float total = 0;float avr = 0;int i;for(i = 0; i < MAX_N; i++) {total = total + numbers;}avr = total / MAX_N;return(avr);}int main(void){float numbers = {0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1};float avr;avr = average(numbers);printf("The average is: %.1f\n", avr);exit(0);}The most critical changes for me from the original code is the following line, since it is buffer overflow and leads security risk.FromCode:for(i = 0; i <= 10; i++)ToCode:for(i = 0; i < 10; i++)

author: fanOfeeDIY
author_rank: Unknown
timestamp: August 14, 2020, 05:05:50 am
content: This is probably out of scope but for the practical usage, probably I would not use float for the averaging.If the all values are know to be point tenth values, then I would multiple all the value by ten,and then average them and divide by ten to speed up the averaging.

author: fanOfeeDIY
author_rank: Unknown
timestamp: August 14, 2020, 05:07:23 am
content: I hope my program gives the correct value. I have not checked it yet...

author: Nominal Animal
author_rank: Super Contributor
timestamp: August 14, 2020, 09:12:01 am
content: Quote from: Cujo on August 14, 2020, 02:48:25 amThe recommended, future-proof way isdouble average(const double *const values, const size_t count);ordouble average(const double values[], const size_t count);which happen to beequivalent.In standard hosted C environments (meaning, on computers on OSes like Windows, Linux, or Mac OS),doubleis the recommended floating-point type, and is usually implemented as aIEEE 754-2008 Binary64; whereasfloatis usuallyIEEE 754-2008 Binary32, and gets promoted todoublein many situations. (See e.g.C11 final public draft n1570, 6.3.1.8p2: "The values of floating operands and of the results of floating expressions may be represented in greater range and precision than that required by the type; the types are not changed thereby", except for explicit casts as noted in a footnote.)Except forsizeof,_Alignof, and address-of&operators, and string literals used to initialize an array, array names decay to a pointer to its first element (n1570, 6.3.2.1p3). This means that if you havedouble numbers;, you can supplynumbersto anything that expects either an array of doubles, or a pointer to double, because the two are equivalent (except for the four exceptions listed above).Because C only knows array sizes/boundaries at compile time, and only within the scope the array was declared in, we need to pass the size of the array, or rather the number of elements we want to calculate the average of, to the average function. The type used for such counts issize_t, notintorlong. (In 64-bit Linux, Windows, and Mac OS,intis 32-bit, butsize_tis 64-bit. In other words, if you useint, which is signed, on these operating systems you limit your array size to 231-1 = 2,147,483,647 items maximum. Sometimes that is acceptable, other times not. You cannot declare that large an array statically, but you can allocate an array of that size, or much larger, dynamically usingmalloc().)Theconstkeyword means "the programmer promises not to modify the value in this scope". It used to help compilers generate better code, but nowadays most C compilers can infer such promises directly from the code. Yet, these promises are very useful for ushumans, because it expresses ourintent: what we want the code to accomplish.(A side note: Try to write comments that explain your idea, your reasoning, as to what the code should accomplish. For example, just before the implementation of theaverage()function, you could add a comment block that says "Calculate the arithmetic mean of the 'count' values in 'numbers' array." Never, ever write comments that tell what the code does; always tell what the reason is that this code exists. After decades of being a professional programmer, I still cannot express how much more important this kind of commenting skill is, than being able to optimize code or write tricky code. It is a skill worth more than any IOCCC win or anything like that.)When you interpret more complex type definitions, split them at the asterisks (reading it as"is a pointer to"), and read the types from right to left.So, for example,const double value[];reads as"value is an array of doubles that won't be modified in this scope". In other words, the code can access the array members to see what value each member has, but promises not to try and modify any of the values therein.Or, for example,const double *const value;reads as"value won't be modified in this scope, and is a pointer to double(s) that won't be modified in this scope".Here, we promise that we won't try to change wherevaluepoints to (the right-sideconst), and we also won't try to modify the values there (the left-sideconst). Simples; plus, it always works, because that's how the C language types work.(The only "exception", or rather variant, is function pointers, but there we use parentheses () to separate the function pointer part and the function argument parts, with the function return type part leftmost without any parentheses usually. So, the rule actually works even for these, there's just additional function-pointer specific stuff added on top.)Because the count is of type size_t, the way I'd implement the averaging function isCode:double average(const double numbers[], const size_t count){double sum = 0.0;size_t i;for (i = 0; i < count; i++) {sum += numbers;}return sum / (double)count;}Here, the(double)countis acast, converting the value ofcounttodoubletype. It is not strictly needed, because C arithmetic promotion rules (n1570 6.3.1.8) automatically promotes it todoublebecausesumis a double. It is arguable whether you should or should not use it here; I only kept it here so you could see what one looks like. They're very commonly used in such cases.(For example, let's say you haveint n;andint d;and you want to calculate their ratio intodouble r;. If you user = n / d;, the division is integer division, andrwill be the integer division result (i.e., an integer) converted todouble. But, if you user = (double)n / d;orr = n / (double)d;orr = (double)n / (double)d;, all three being exactly equivalent in this case, you'll get the best approximation of the ratio a double-precision floating point number can describe.)The function itself does not print anything, it just calculates the arithmetic mean (average), and returns it as adouble. This is recommended, because then you keep functionality in logically separated units, and can test the function (for example in a separate program) with known data to see if it works correct.Typical bugs are off-by-one kind, likefor (i=1; i < n; i++)andfor (i=0; i<=n; i++). Verifying with known data can help catch these.In the main program, you'd have for exampleCode:double mynums[] = { 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1 };double avg;avg = average(mynums, sizeof mynums / sizeof mynums);printf("%.1f\n", avg);Here, we use the "number of elements in an array declared in the current scope" trick.sizeof mynumsis the size of the entire array in bytes (chars), andsizeof mynumsis the size of the first element in bytes (chars), sosizeof mynums / sizeof mynumsis the number of elements in the array.This does not work in a function, because the array declaration is in the function parameter. This only works as a shorthand in the same scope (function or block) where the actual array was defined in.For example, if you haveint example(int array), inside the function definitionsizeof array / sizeof arraywill always evaluate to 15, regardless of what was passed to the function. And, if you useint example(int array[]), trying to usesizeof arrayinside the function will make your compiler complain or error. (With GCC, it'll return the size of a pointer to an int.) Simply put, there is no shortcut. If you pass an array as a parameter, you should always also pass the size of that array, too.Okay, so you managed to read this far. Do I expect you to understand all that at once? No, not really; a lot of it is something that being vaguely aware of when learning the details will keep you on the right track, and will usually help things "click in place" well when you do learn them. All this is meant as a "oh, sothatis what that Nominal Animal was babbling about;nowit makes sense!" type of thing, and involves the core issues on the "hard stuff" I've seen when trying to help others learn C.

author: greenpossum
author_rank: Frequent Contributor
timestamp: August 14, 2020, 10:10:21 am
content: The WoTs have started. I'm outta here.