Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [24]
void cartesianToPolar(float x, float y, float *rPtr, float *thetaPtr)
That is, when the function is called, it will be passed values for x and y. It will also be supplied with locations where the values for radius and theta can be stored.
Now write the function near the top of your main.c file and call it from main():
#include #include void cartesianToPolar(float x, float y, double *rPtr, double *thetaPtr) { // Store the radius in the supplied address *rPtr = sqrt(x * x + y * y); // Calculate theta float theta; if (x == 0.0) { if (y == 0.0) { theta = 0.0; // technically considered undefined } else if (y > 0) { theta = M_PI_2; } else { theta = - M_PI_2; } } else { theta = atan(y/x); } // Store theta in the supplied address *thetaPtr = theta; } int main(int argc, const char * argv[]) { double pi = 3.14; double integerPart; double fractionPart; // Pass the address of integerPart as an argument fractionPart = modf(pi, &integerPart); // Find the value stored in integerPart printf("integerPart = %.0f, fractionPart = %.2f\n", integerPart, fractionPart); double x = 3.0; double y = 4.0; double radius; double angle; cartesianToPolar(x, y, &angle, &radius); printf("(%.2f, %.2f) becomes (%.2f radians, %.2f)\n", x, y, radius, angle); return 0; } Build and run the program. Figure 9.3 The stack as cartesianToPolar() returns Avoid dereferencing NULL This means that you should always check to make sure the pointers are non-NULL before you dereference them. Add these checks in cartesianToPolar(): void cartesianToPolar(float x, float y, double *rPtr, double *thetaPtr) { // Is rPtr non-NULL? if (rPtr) { // Store the radius in the supplied address *rPtr = sqrt(x * x + y * y); } // Is thetaPtr NULL? if (!thetaPtr) { // Skip the rest of the function return; } // Calculate theta float theta; if (x == 0.0) { if (y == 0.0) { theta = 0.0; // technically considered undefined } else if (y > 0) { theta = M_PI_2; } else { theta = - M_PI_2; } } else { ... 10 Structs Now you’re going to create your own Person type. A variable of type Person will be a structure and will have two members: a float called heightInMeters and an int called weightInKilos. Create a new project: a C Command Line Tool called BMICalc. Edit main.c to create a structure that contains the data you need for a person: #include // Here is the declaration of the struct Person struct Person { float heightInMeters; int weightInKilos; }; int main(int argc, const char * argv[]) { struct Person person; person.weightInKilos = 96; person.heightInMeters = 1.8; printf("person weighs %i kilograms\n", person.weightInKilos); printf("person is %.2f meters tall\n", person.heightInMeters); return 0; } Notice that you access the members of a struct using a period. Here’s the frame for main() after the struct’s
Sometimes a function can supply many values by reference, but you may only care about some of them. How do you avoid declaring these variables and passing their addresses when you’re not going to use them anyway? Typically, you pass NULL as an address to tell the function “I don’t need this particular value.”
Sometimes you need a variable to hold several related chunks of data. For example, imagine that you were writing a program that computed a person’s Body Mass Index. (What is your BMI? It is your weight in kilograms divided by the square of your height in meters. A BMI under 20 suggests that you may be underweight. A BMI over 30 suggests that you may be obese. It is a very imprecise tool for measuring a person’s fitness, but it makes a fine programming example.) A person, for your purposes, consists of a float that represents height in meters and an int that represents weight in kilograms.