What's Your Function?
Pages: 1, 2
Build and Run
So before we play around with this code that we just read through, let's give it a whirl.
Up at the top of the window, in the toolbar, there is an icon that looks like this if you're running Project Builder:
And like this if you're running Xcode:
This is the "Build and Run" button, which will compile the project that you're working on (make the code into language the computer can execute), and then run the program you made. If you click this now, you will build and run the code contained in this project, which is just the main function we've examined. Do this now, and watch the computer execute the code, printing the message into the window (in Xcode, you have to go to the Debug menu and select Show Run Log to see the message). If you get an error, make sure that everything is copied exactly.
So that's what you can do without writing a single line of code. But we already have a few lines of code sitting around from our last lesson, so let's pull those out and give them a whirl. Delete the comment and the call to printf, and paste in our code. Now your main.c file should contain this:
#include <stdio.h>
int main (int argc, const char * argv[]) {
//Computes our favorite number
int favoriteNumber = (3 * 4) / 2; //is anyone's favorite number not an int?
favoriteNumber = favoriteNumber + 2;
/* now let's tell the world
what our favorite number is! */
printf("My favorite number is %d!", favoriteNumber);
return 0;
}
And again, click the Build and Run button (remember that if you're in Xcode, you have to select Show Run Log from the Debug menu). Now, instead of "Hello, World!", what prints is "My favorite number is 8!" And you made it print that.
But what else can you make it do? We'll explore our boundaries a little bit by defining our own function. So below the main function, put the following snippet of code:
int integerForSeedValue(int seedNumber) {
//code goes here
}
This is another function definition, so called because it defines exactly what the function does. There are a few things to notice here, the first being that the name of the function follows the same style we use for variables: take all of the words that make up what you're describing, smash them together with each word capitalized, and make the first letter lowercase.
Notice also that our function has one argument, and that argument is described in the parentheses. Our code defines its type, which is an int, and we give it a name, seedNumber, which again follows our variable-naming scheme. Every time we want to call this function, we must pass one integer into it, or the compiler will complain and the program will crash.
Note where the curly brackets are placed. This method is the traditional C style, with the opening bracket on the same line as the function name. Objective-C uses this same style, but C++ puts the opening bracket on the next line, all alone. Since C ignores whitespace, both are perfectly legal, and since a lot of people use C++ a lot, they're more used to it down there on the next line. So don't be alarmed if you see it move around a bit.
Lastly, we're returning an integer, but we have no code that says what we're returning. This is obviously a problem, but before we fix our function up, let's hit the Build button and see what the Developer Tools think. We want to build and not run for right now, because our code is not correct, and we need to see how the Developer Tools inform us of this fact. The Build button looks like this in Project Builder:
And like this in Xcode:
When you hit the Build button, the project window moves around a bit to make it obvious it's doing something. In Project Builder, an area opens up to tell you about how the build is going. In Xcode, the Errors and Warnings item on the left will open up. In either case, you will see the message warning: control reaches end of non-void function.
What's this? It's a warning. Warnings tell you that while the compiler was trying to understand your code, something seemed a little odd, and it decided to tell you about it. This warning tells you that you have made a function whose definition claims the function returns a value (an int, in our case), but the function body doesn't ever return anything. That would be just fine in a void function (which we'll get to later), but it's a little odd here, so the compiler gives you a warning. An error is a more serious problem that means that your code cannot be compiled as written, and you need to fix the problem before you can run. Both show up in the same places, but warnings will allow you to run your program, although they often foretell errors that will crash your program at run time. Click on the text and the developer tools will helpfully take you to the offending piece of code. For now, it's obvious that our new function is the culprit, but in huge projects, this click-and-go is a lifesaver.
For now we have a simple fix to our problem. We simply add a line into our function, so it looks like this:
int integerForSeedValue(int seedNumber) {
//code goes here
return 0;
}
Click Build again, and you will see that the warning disappears. It is a good practice to write code that has neither warnings nor errors, and we will strive to do this as we complete more complex code.
Spice Up the Function (Just for Fun)
But for now you may wonder about our little fix. Our function ignores the input we give it, doesn't do anything useful, and always returns the same thing. What is this, a Windows error dialog?
So let's spice up our function a little. Change the function to the following:
int integerForSeedValue(int seedNumber) {
return seedNumber - 3;
}
Now we're doing some work in our function, and we're returning something that changes, based on what we're given. We return the variable seedNumber, minus the constant 3. But you might be wondering how we can use the variable seedNumber without first issuing a variable declaration, and that is a very good question. The answer is that we did a variable definition, it's just not as visible as the others we have done. This definition is inside of the parentheses, in the argument list. There, when we note what arguments this function takes, we are also declaring these arguments to exist.
So now that we have a function, we need to call it. Up in our main function, replace the line
favoriteNumber = favoriteNumber + 2;
with the slightly altered line:
favoriteNumber = integerForSeedValue(favoriteNumber + 2);
Now we're calling our integerForSeedValue function from our main function. When the computer executes that line of code, it will look into our integerForSeedValue function and run all of the code in its code block before moving on to the next line of code in main. Note that while the computer is executing the lines in integerForSeedValue, the variable seedNumber will have the evaluated value of favoriteNumber + 2, which is 8. So integerForSeedValue will return 8-3, or 5. Let's build our program and see. Hit the Build button, to make sure we don't have any warnings or errors.
Well, what do you know? We do. The warning we got this time is warning: implicit declaration of function `integerForSeedValue'. What does that mean? Well, we know what a variable declaration is, and we know that we can't use variables until we declare them. And if we click on this warning, it takes us to where we're using our function, so it's a pretty logical step to think that functions need to be declared before use, too, and that's exactly right.
So we add in one line above main, to declare our function. Now our file looks like this:
#include <stdio.h>
int integerForSeedValue(int seedNumber);
int main (int argc, const char * argv[]) {
//Computes our favorite number
int favoriteNumber = (3 * 4) / 2; //is anyone's favorite number not an int?
favoriteNumber = integerForSeedValue(favoriteNumber+2);
/*now let's tell the world
what our favorite number is! */
printf("My favorite number is %d!", favoriteNumber);
return 0;
}
int integerForSeedValue(int seedNumber) {
return seedNumber - 3;
}
Looks familiar, doesn't it? What we've done is take the function, knock it's block off, and present it here with a semicolon. That is enough for the compiler; this simple line is the function declaration we needed, and another Build confirms it when the compiler doesn't complain. Run the program, and you see that our favorite number is now 5, just like it should be!
Wrapping Up
Wow, we've made some progress in this lesson! We learned about the tools we'll need to use every day we're developing, we compiled and ran "Hello World!", we took a few lines of code and made it into a program, we learned how to recognize, implement, declare, and call functions, and we learned how to get information from the Developer Tools about problems with our code, and fix them before they're problems with our programs.
But we still have a long ways to go. Next time, we'll dive into flow control, which affect the way our code gets executed, so we can do more complex things than the "list of things to do" approach we have been taking. That will give us a lot of the tools we need to make more complex programs with the knowledge we've gained.
Seth Roby graduated in May of 2003 with a double major in English and Computer Science, the Macintosh part of a three-person Macintosh, Linux, and Windows graduating triumvirate.
Read more Programming With Cocoa columns.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 13 of 13.
-
Can't wait for the next lesson!
2003-08-15 02:06:02 anonymous2 [Reply | View]
This is exactly what I need.
-
Just what newbies need!
2003-08-08 21:49:42 anonymous2 [Reply | View]
Where were these articles when I started learning Cocoa this spring? ;-)
You could have saved me a pile of money on books (including Schildt's TEACH YOURSELF C, which is very pedagogical, but is also MS centric).
tssfulk
PS. One annoying nitpick on the HTML. It doesn't view nicely with Safari on an iBook. I had to scroll left and right to read the text. I used the printer friendly version, which worked nicely, but I shouldn't have to do that.
-
rolling my own, then resting in columns
2003-08-05 08:26:28 psheldon [Reply | View]
I am getting into modifying Apple sample code, but I find it always refreshing to just have something done for me, for balance.
Last night, I thought up my second controller object (which some say is different from and better than a function) that will speed up my doing repetitive aspects of programming modification. The structural element, object in object oriented programming, say objective c, that receives messages is an extension of the already fertile notion function.
I am excited to start rolling my own structural elements to build with, making my own examples, but like just following a column too. I had to run through many examples before I had the nerve to do this for myself. I still get pleasure reading examples fast to see how the subject is put together from perhaps another slant.
You clean up and finish elements of structures and this gives satisfaction much as having little milestones on the way to a goal. Then you put together just the calls to the pieces which speeds approaching the goal.
I need to recall a separate utility of functions from objects being sent messages. Sometimes I would want to use one and other times the other. Functions haven't been canned in lieu of objects, they coexist in the language. Perhaps only examples of alternate styles both working together and improving on each other can get me this feel.
An old text of examples of good and bad style breaking problems into functions by Ledgard, "Programming Proverbs : Pascal with Style", was very exciting. This text first gave me the impression developing style can help me solve humungous problems, a powerful experience.
Oreilly Network's columns have also been a powerful and confidence building experience.
In fact, I am happy to find I can put my own "two bits" into Apple openGL code examples and this makes me feel functional in individual input rather than merely following everyone else's thing. That's a bit of the confidence I got to with Oreilly Network's columns.
Hope I've inspired here.
-
Yeah, let's do some Flow Control!
2003-08-02 00:41:54 anonymous2 [Reply | View]
Thanx for this episode -- I grokked it easily. Looking forward to the next lesson.
-
Great!
2003-08-01 18:36:04 anonymous2 [Reply | View]
I have run my first C program, hurrah! I even dared add a "seedNumber--;" instruction...
Thanks for a great tutorial which is exactly at the level I need.
-
C is not functional
2003-08-01 17:47:20 anonymous2 [Reply | View]
C is almost entirely an imperative, or procedural, language. The easiest way to determine which type a language is predominantly is by looking at it's variables. If a language performs most computation through the manipulation of variables, it is imperative. If a language performs most computation without the manipulation of variables, it is functional.
C is an imperative language.
Lisp is a functional language. -
Your comment is inappropriate...
2003-08-02 00:37:58 anonymous2 [Reply | View]
...given the audience this is geared at. Given my background in the subject (which I will assume is generaly consistent with the vast majority of people reading this column), I can't even fathom how profound and important your correction is. Maybe next time you can save the learned computer science nit picking for a column that doesn't focus extensively on "hello world".
Please keep the columns coming - they are quite good. At this pace I'll soon be able to troll neophyte-geared columns with my vast knowledge aching to drip from my fingertips... -
Honestly not trying to troll
2003-08-02 11:19:39 anonymous2 [Reply | View]
While I was somewhat brusk, I was not trying to provoke responses. I was trying to convey a rather complicated difference as simply as I could.
A beginning programmer is not going to care if what he is told is wrong, perhaps, but it will hinder his continued learning as he has to relearn concepts as he goes along.
In some subjects, this is done intentionally, such as physics, where galilean relativity is taught despite it being wrong, and only when special relativity is taught are the (more) correct concepts discussed.
I do not think this applies so well in this case. The article would have been just as useful if it had discussed the use of subroutines (a more apt name for the behavior involved), and perhaps touched briefly on how a function is a subroutine without a side effect.
I tried to present a way of telling the difference between the two as simply as I could, with a concrete example for each. I apologize if I was rude.





