Abnormal program termination

E

ehabaziz2001

I am facing that error message with no idea WHY the reason ? "Abnormal
program termination"



E:\programs\c_lang\iti01\tc201\ch06\own> arr01o01
Enter a number : 25
More numbers (y/n)? y
Enter a number : 30
More numbers (y/n)? n
25.000000
30.000000
The average is 27.500000
Abnormal program termination

E:\programs\c_lang\iti01\tc201\ch06\own>type arr01o01.c

/*#include <stdio.h>
/*-exercise 6.1.1 - calculate average of a series of numbers*/
main ()
{
float number[100];
int no_numbers,i;
float ave(),average;
input_nos(&no_numbers,number);
average=ave(no_numbers,number);
print_nos(number,no_numbers,average);
}

input_nos(count,nos)
int *count;
float *nos;
{
char another_no;
*count=0;
do
{
++(*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);
}


float ave(n_n,n)
int n_n;
float *n;
{
float total=0;
int i;
for (i=0;i<=n_n;i++)
total=total+n;
return(total/n_n);
}


print_nos(nu,n_n,a)
int n_n;
float *nu,a;
{
int i;
for (i=1;i<=n_n;i++)
printf ("%f\n",nu);
printf ("\n The average is %f \n",a);
}
 
J

jacob navia

I am facing that error message with no idea WHY the reason ? "Abnormal
program termination"



E:\programs\c_lang\iti01\tc201\ch06\own> arr01o01
Enter a number : 25
More numbers (y/n)? y
Enter a number : 30
More numbers (y/n)? n
25.000000
30.000000
The average is 27.500000
Abnormal program termination

E:\programs\c_lang\iti01\tc201\ch06\own>type arr01o01.c

/*#include <stdio.h>
/*-exercise 6.1.1 - calculate average of a series of numbers*/
main ()
{
float number[100];
int no_numbers,i;
float ave(),average;
input_nos(&no_numbers,number);
average=ave(no_numbers,number);
print_nos(number,no_numbers,average);
}

input_nos(count,nos)
int *count;
float *nos;
{
char another_no;
*count=0;
do
{
++(*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);
}


float ave(n_n,n)
int n_n;
float *n;
{
float total=0;
int i;
for (i=0;i<=n_n;i++)
total=total+n;
return(total/n_n);
}


print_nos(nu,n_n,a)
int n_n;
float *nu,a;
{
int i;
for (i=1;i<=n_n;i++)
printf ("%f\n",nu);
printf ("\n The average is %f \n",a);
}


The first problem is that the "count" pointer did NOT receive any
storage to hold the values you are storing

The second problem is that the "nos" pointer did not receive any storage
for storing the numbers you enter.

Then the program crashes.

Use:
int count = 0;

#define MAX_INPUT 100
float nos[MAX_INPUT];

And when reading a number, test that you
do not exceed the MAX_INPUT value
 
R

Richard Heathfield

jacob navia said:

The first problem is that the "count" pointer did NOT receive any
storage to hold the values you are storing

Read the program again, more carefully.
The second problem is that the "nos" pointer did not receive any storage
for storing the numbers you enter.

Read the program again, more carefully.

And when reading a number, test that you
do not exceed the MAX_INPUT value

Read the program again, more carefully.
 
L

Lew Pitcher

I am facing that error message with no idea WHY the reason ? "Abnormal
program termination"



E:\programs\c_lang\iti01\tc201\ch06\own> arr01o01
Enter a number : 25
More numbers (y/n)? y
Enter a number : 30
More numbers (y/n)? n
25.000000
30.000000
The average is 27.500000
Abnormal program termination

E:\programs\c_lang\iti01\tc201\ch06\own>type arr01o01.c

/*#include <stdio.h>
/*-exercise 6.1.1 - calculate average of a series of numbers*/
main ()
{
float number[100];
int no_numbers,i;
float ave(),average;
input_nos(&no_numbers,number);
average=ave(no_numbers,number);
print_nos(number,no_numbers,average);
}

Repeat after me: "main() returns an int, so we must supply an int for
it to return."

What happens if you /don't/ return an int out of main()?
Well, "Abnormal program termination" is one possible answer.

[snip]

HTH
 
C

Christopher Benson-Manica

/*#include <stdio.h>

Um, that's a problem.
/*-exercise 6.1.1 - calculate average of a series of numbers*/
main ()

int main(void). See Lew's response.
input_nos(count,nos)
int *count;
float *nos;

void input_nos( int *count, float *nos )

Your form is (I believe) legal, but you can see why the above is much
preferred.
 
E

Eric Sosman

I am facing that error message with no idea WHY the reason ? "Abnormal
program termination"

The proximate cause is *probably* that you "fall off the
end" of the main() function without telling it what value to
return. main() returns an `int' value that indicates the
program's "exit status;" what *probably* happened is that by
falling off the end you returned some kind of garbage value
as your program's exit status. When your operating system saw
that the exit status was something weird, it warned you that
the program had terminated abnormally.

See below for the cure and a few other hints.
/*#include <stdio.h>

Don't comment this out; you need it.
/*-exercise 6.1.1 - calculate average of a series of numbers*/
main ()

Better style would be `int main(void)', which says
explicitly that main() takes no arguments and returns an
int value.
{
float number[100];
int no_numbers,i;
float ave(),average;
input_nos(&no_numbers,number);
average=ave(no_numbers,number);
print_nos(number,no_numbers,average);

... and here's where you need to return a value as the
program's exit status. The value zero means "successful
completion," so add `return 0;' here.
}

input_nos(count,nos)
int *count;
float *nos;

This is known as the "old-style" or "K&R" method of
describing a function's arguments. In 1989 a new style
was added to the language, and the new method is a much
better way to do things. The old style is still supported
so as not to invalidate the reams and reams of C code that
were written before 1989, but when you write new code there
is virtually no reason to use the old style. Write

void input_nos(int *count, float *nos)

This says that input_nos is a function of two arguments, just
as the old style did, but it also makes the types of those
arguments "visible" to the rest of the program instead of only
inside the function. This allows the compiler to catch silly
mistakes, like accidentally interchanging the arguments when
you call the function. Also, the `void' at the beginning says
this is a function that returns no value.

The only drawback to this style is that you must (usually)
declare the function before you call it, and that might require
writing one extra line of code. Alternatively, you could just
move the function definition up near the top of the source file
("the Pascal disease"), because the definition will also serve
as a declaration.
{
char another_no;
*count=0;
do
{
++(*count);
printf("Enter a number : ");

On some systems you may have trouble getting your
prompts to display properly; see Question 12.4 in the
comp.lang.c Frequently Asked Questions (FAQ) list at
http://c-faq.com/.
scanf("%f",&nos[*count]);

See Question 12.20 in the FAQ.
if (*count<100)
{
printf("More numbers (y/n)? ");
scanf("\n");
scanf("%c",&another_no);
}
}
while (another_no=='y'&&(*count)<100);

There's an off-by-one error in this loop. Array indices
in C begin with [0], yet this loop starts storing the values
at index [1]. Worse, it would allow a sufficiently patient
typist to try to store a value at index [100], but your 100-
element array stops after index [99]. If the attempt is made,
there is no telling what might happen.
}


float ave(n_n,n)
int n_n;
float *n;

Same comment about "old-style" and "new-style." This
time you would write `float ave(int n_n, float *n)'.
{
float total=0;
int i;
for (i=0;i<=n_n;i++)

Off-by-one error again, but a slightly different one.
This time you include all the indices [0] through [n_n]
in the total, but (because of the earlier error) no value
has been stored in the [0] element. From your program's
output it appears you were lucky and the [0] element just
happened to contain a zero, but you cannot rely on being
lucky every time. Your program might have told you that
the average of 25 and 30 is -42.424242, or might have done
something even stranger.
total=total+n;
return(total/n_n);
}


print_nos(nu,n_n,a)
int n_n;
float *nu,a;


Same comment about old-style and new style. This time,
you'd write `void print_nos(float *nu, int n_n, float a)'.
{
int i;
for (i=1;i<=n_n;i++)

This matches the off-by-one error in the input loop,
so when you correct the former you'll need to change this
one as well.
printf ("%f\n",nu);
printf ("\n The average is %f \n",a);
}
 
C

Christopher Benson-Manica

This is known as the "old-style" or "K&R" method of
describing a function's arguments.

With no return type specified, does the return type not default to
int? If that's so, then isn't it UB to fail to return a value from a
function that is declared to return one? Or is there some special
dispensation for old-style declarations?
 
R

Richard Heathfield

(e-mail address removed) 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.h> inclusion!

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;
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);
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);

And there we have it. This loop needs to be changed to:

for(i = 0; i < n_n; i++)
printf("%f\n", nu);

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!
 
E

Eric Sosman

Christopher Benson-Manica wrote On 09/01/06 10:01,:
With no return type specified, does the return type not default to
int? If that's so, then isn't it UB to fail to return a value from a
function that is declared to return one? Or is there some special
dispensation for old-style declarations?

It's U.B. only if the caller attempts to use the
value that wasn't returned.

int falloff(void) { /* no return */ }
...
falloff(); /* no U.B. */
x = falloff(); /* U.B. */

One exception: In C99, falling off the end of main()
returns a zero, or behaves as if it did. (I can't be
bothered to look up whether that's only for the initial
call, or also applies to recursive calls.) Apparently
the O.P. was not using a C99 compiler -- his code has
other evidences of non-C99-ness, too.
 
W

Walter Roberson

Christopher Benson-Manica wrote On 09/01/06 10:01,:
It's U.B. only if the caller attempts to use the
value that wasn't returned.
One exception: In C99, falling off the end of main()
returns a zero, or behaves as if it did.

In C89, a return from the initial call to main() without
specifying a termination status, results in an undefined termination
status being returned to the host environment.

The C standard does not really define what it means to return any
particular status to the host environment. There are the specific
values to indicate success or failure, but as far as C is concerned,
even if you indicate success the host environment could produce
a coredump or walk a disc array off the raised floor or whatever.
The result is thus undefined in any case ;-) (But it'd probably
take a DS 9000 Mark II to act maliciously if the success status
is returned.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,188
Latest member
Crypto TaxSoftware

Latest Threads

Top