eh**********@gmail.com said:
I am facing that error message with no idea WHY the reason ? "Abnormal
program termination"
<code snipped>
The first thing I did was to compile your program. Here is the list of
diagnostic messages my compiler issued:
foo.c:2: warning: `/*' within comment
foo.c:4: warning: return-type defaults to `int'
foo.c:4: warning: function declaration isn't a prototype
foo.c: In function `main':
foo.c:7: warning: function declaration isn't a prototype
foo.c:7: warning: nested extern declaration of `ave'
foo.c:8: warning: implicit declaration of function `input_nos'
foo.c:10: warning: implicit declaration of function `print_nos'
foo.c:6: warning: unused variable `i'
foo.c:11: warning: control reaches end of non-void function
foo.c: At top level:
foo.c:14: warning: return-type defaults to `int'
foo.c:14: warning: function declaration isn't a prototype
foo.c: In function `input_nos':
foo.c:22: warning: implicit declaration of function `printf'
foo.c:23: warning: implicit declaration of function `scanf'
foo.c:32: warning: control reaches end of non-void function
foo.c: At top level:
foo.c:36: warning: function declaration isn't a prototype
foo.c:48: warning: return-type defaults to `int'
foo.c:48: warning: function declaration isn't a prototype
foo.c: In function `print_nos':
foo.c:55: warning: control reaches end of non-void function
I fixed the first problem by removing the /* from the first line - you were
"commenting out" the <stdio.hinclusion!
The second problem was fixed easily enough, by changing
main ()
to
int main(void)
Your version is legal under C90 rules, but int main(void) is more explicit
about the return type and parameter list.
I fixed these two lines:
foo.c:7: warning: function declaration isn't a prototype
foo.c:7: warning: nested extern declaration of `ave'
by replacing:
float ave(), average;
with
float average;
and placing
float ave(int, float *);
above the main function. Again, your version is actually legal, but the
version given here is more explicit about its types.
Your input_nos() and print_nos() functions had no prototypes, so I added
some:
int input_nos(int *, float *);
int print_nos(float *, int, float);
I changed
int no_numbers,i;
to
int no_numbers;
I added
return 0;
as the last line of main. I changed your (correct, but ancient) K&R-style
function declarator from:
input_nos(count,nos)
int *count;
float *nos;
to the more modern "prototype" style:
int input_nos(int *count, float *nos)
Since input_nos is defined as returning int (which was implicit until I made
it explicit), it needs to return a value, so I added:
return 0;
at its end. Similarly, I changed:
float ave(n_n,n)
int n_n;
float *n;
to:
float ave(int n_n, float *n)
and:
print_nos(nu,n_n,a)
int n_n;
float *nu,a;
to:
int print_nos(float *nu, int n_n, float a)
and added:
return 0;
to its end.
Having made all these modifications, I got a clean compile. I then ran the
code through an indenting tool. Here is the result:
#include <stdio.h>
/*-exercise 6.1.1 - calculate average of a series of numbers*/
float ave(int,
float *);
int input_nos(int *,
float *);
int print_nos(float *,
int,
float);
int main(void)
{
float number[100];
int no_numbers;
float average;
input_nos(&no_numbers, number);
average = ave(no_numbers, number);
print_nos(number, no_numbers, average);
return 0;
}
int input_nos(int *count,
float *nos)
{
char another_no;
*count = 0;
do
{
/* REFER TO EXPLANATION AND CORRECTION, LATER IN ARTICLE */
++(*count);
printf("Enter a number : ");
scanf("%f", &nos[*count]);
if(*count < 100)
{
printf("More numbers (y/n)? ");
scanf("\n");
scanf("%c", &another_no);
}
}
while(another_no == 'y' && (*count) < 100);
return 0;
}
float ave(int n_n,
float *n)
{
float total = 0;
int i;
/* REFER TO EXPLANATION AND CORRECTION, LATER IN ARTICLE */
for(i = 0; i <= n_n; i++)
total = total + n[i];
return (total / n_n);
}
int print_nos(float *nu,
int n_n,
float a)
{
int i;
/* REFER TO EXPLANATION AND CORRECTION, LATER IN ARTICLE */
for(i = 1; i <= n_n; i++)
printf("%f\n", nu[i]);
printf("\n The average is %f \n", a);
return 0;
}
The next step was to attempt to fix your problem! Running the code and using
your test data, I didn't get "Abnormal program termination", but I did get
- the wrong answer! I entered 25 and 30, just like you did, but got a
result of 28.510899, which is clearly wrong. So I had something to debug.
Good.
The first thing to check is that you're using the array properly. At this
point in the discussion, it actually makes sense to take one of Mr Navia's
suggestions seriously [1], and introduce a symbolic constant for the number
of elements in the array:
#define MAX_INPUT 100
We then change the definition of number to:
float number[MAX_INPUT];
and
if(*count < 100)
becomes
if(*count < MAX_INPUT)
Finally:
while(another_no == 'y' && (*count) < 100);
becomes:
while(another_no == 'y' && (*count) < MAX_INPUT);
Let's remember that array elements are counted from 0. That is, number[0] is
the first element. If our array has 100 elements, then, the valid indices
are 0 through 99.
So we want our first write to be to element 0, yes?
In input_nos(), we find this code:
*count = 0;
Index is 0.
do
{
++(*count);
Index is now 1.
printf("Enter a number : ");
scanf("%f", &nos[*count]);
First write goes into element 1! That isn't what we want, so let's fix it:
*count = 0;
do
{
printf("Enter a number : ");
scanf("%f", &nos[*count]);
++(*count);
This time, when we run the program, we get:
me@here./foo
Enter a number : 25
More numbers (y/n)? y
Enter a number : 30
More numbers (y/n)? n
30.000000
2.021596
The average is 28.510798
which is clearly still wrong, so let's continue our analysis by looking at
the average-calculating function, which accepts the number of valid data
and a pointer to the first element in the data array:
float ave(int n_n,
float *n)
{
float total = 0;
int i;
for(i = 0; i <= n_n; i++)
Wait a minute, though - this counts from 0 to n_n. If we have 1 valid
number, it should sum one valid number, i.e. n[0], but you have it as
summing n[0] and n[1]. If you have two numbers, it should sum two numbers -
n[0] and n[1] - but you have it summing three, because you include n[2] as
well. So let's fix that to:
for(i = 0; i < n_n; i++)
....I've changed <= to < so that it sums exactly the right amount of data.
me@here./foo
Enter a number : 25
More numbers (y/n)? y
Enter a number : 30
More numbers (y/n)? n
30.000000
2.021596
The average is 27.500000
Now the /result/ is right, which is good, but the displayed data are wrong.
Specifically, the first one displayed is n[1] rather than n[0], and the
second one is just completely out to lunch. That smacks of an off-by-one
error in the display routine. So let's go look for it:
int print_nos(float *nu,
int n_n,
float a)
{
int i;
for(i = 1; i <= n_n; i++)
printf("%f\n", nu[i]);
And there we have it. This loop needs to be changed to:
for(i = 0; i < n_n; i++)
printf("%f\n", nu[i]);
This final modification gives us the correct answer. To give you some
confidence that this is the case, I averaged four numbers:
me@here./foo
Enter a number : 1
More numbers (y/n)? y
Enter a number : 3
More numbers (y/n)? y
Enter a number : 7
More numbers (y/n)? y
Enter a number : 29
More numbers (y/n)? n
1.000000
3.000000
7.000000
29.000000
The average is 10.000000
Unfortunately, we're not done yet. Observe:
me@here./foo
Enter a number : TEN
More numbers (y/n)? 2.021797
The average is 2.021797
Clearly that's unacceptable. We need to be able to handle this problem, so
let's introduce a fix:
scanf("%f", &nos[*count]);
becomes:
if(scanf("%f", &nos[*count]) != 1)
{
puts("Invalid data. Quitting.");
exit(EXIT_FAILURE);
}
which necessitates the following additional line at the top of the program:
#include <stdlib.h>
Now, when we try to mess the program about, we get this:
Enter a number : TEN
Invalid data. Quitting.
and the program terminates.
I hope you find the above helpful.
[1] Gosh!
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)