Welcome to the world of error handling. So basically you want to return an optional value - either the value if valid and you want to return the value or the value is invalid and want to return an error condition.
You can wrap it in a structure, but don't:
struct coef_or_err {
int err;
coefficient coef;
};
struct coef_or_err function() {
if (poly->coef[MAX_DEGREE - expon]){
return (struct coef_or_err){ .err = 0, .coef = poly->coef[expon] };
} else {
return (struct coef_or_err){ .err = 1 };
}
}
But that is a lot of typing and different structures for all possible cases, it's not bearable to maintain such code easily. So it's typical in C to pass additional parameters by pointers. Either passing a pointer to an int that will be an non-zero error code in case of error or most prefer returning an int with value 0 on success and take all other parameters by pointers:
int Coef(Polynomial* poly, int expon, coefficient *coef) {
if (!poly->coef[MAX_DEGREE - expon]) {
return -1; // or some error code, maybe ENOENT from errno.h
}
*coef = poly->coef[expon];
return 0;
}
// example user call
int main() {
coefficient coef;
if (!Coef(some_poly, 15, &coef)) {
// handle error
abort();
}
// use coef
}
Eamples of such error handling can be found in many places. Another type of error handling is using a global variable, either stored in the object or... globally, but please don't (errno and why global variables are bad):
coefficient Coef(Polynomial* poly, int expon) {
if (!poly->coef[MAX_DEGREE - expon]) {
poly->err = 1;
return 0;
}
return poly->coef[expon];
}
int Coef_is_err(Polynomial* poly){
return poly->err;
}
void Coef_clear_err(Polynomial* poly){
poly->err = 0;
}
int main() {
coefficient coef = Coef(some_poly, 15);
if (Coef_is_err(some_poly)) abort();
// use coef
}
The most prominent example is ferror(FILE*) from standard library. Such code is more usefull in case of I/O operations, for example aio_error() from posix.
And yet another way is using out-of-bounds values to transfer errors, typically used when the type can represent more values then are valid for the meaning. For example function returning count of somethings has to return a positive number or zero - a negative would be an error.