Tip 49: return multiple items from a function
07 January 12. [link] PDF version
level: Your functions are getting complex
purpose: separate inputs from outputs
Part of a series of tips on POSIX and C. Start from the tip intro page, or get 21st Century C, the book based on this series.
A mathematical function doesn't have to map to one dimension: mapping to ℜ2 is nothing at all spectacular.
Python lets you return lists, like this:
#Given the standard paper size name, return its width, height def length_width(papertype): if (papertype=="A4"): return [210, 297] if (papertype=="Letter"): return [216, 279] if (papertype=="Legal"): return [216, 356] [a, b] = length_width("A4"); print("width= %i, height=%i" %(a, b))
C won't provide nearly as neat a format, but you can always return a struct, and thus as many subelements as desired. Which is why I was praising the joys of having throwaway structs in the last tip: generating a function-specific struct is not a big deal.
Let's face it: C is still going to be more verbose than languages that have the built-in ability to retun lists. But it is not impossible to clearly express that the function is returning a value in ℜ2.
I decided to write the code sample using the condition ? iftrue : else
form,
which is a single expression, and so can appear after the return. Notice how it
cascades neatly into a sequence of else-if cases (including that last catch-all else clause
at the end). I like to format this sort of thing into a nice little table; you can
find people who call this terrible style.
#include <stdio.h> #include <math.h> //NaN typedef struct { double width, height; } size; size width_height(char *papertype){ return !strcasecmp(papertype, "A4") ? (size) {.width=210, .height=297} : !strcasecmp(papertype, "Letter") ? (size) {.width=216, .height=279} : !strcasecmp(papertype, "Legal") ? (size) {.width=216, .height=356} : (size) {.width=NAN, .height=NAN}; } int main(){ size a4size = width_height("a4"); printf("width= %g, height=%g\n", a4size.width, a4size.height); }
The alternative is to use pointers, which is darn common and not considered bad form, but it certainly obfuscates what is input and what is output, and makes the version with the extra typedef look stylistically great:
//return height and width via pointer: void width_height(char *papertype, double *width, double *height);
or
//return width directly and height via pointer: double width_height(char *papertype, double *height);
[Previous entry: "Tip 48: Limit typedef scope"]
[Next entry: "Tip 50: Optional and named arguments"]