Showing posts with label Beginner C programming Tutorial. Show all posts
Showing posts with label Beginner C programming Tutorial. Show all posts

Wednesday, December 4, 2013

Pointer Parameters and the Address Operator


Objective-C is chock-a-block with pointers (and asterisks), because that’s how Objective-C refers to an object. Objective-C methods typically work with objects, so they typically expect pointer parameters and return a pointer value. But this doesn’t make things more complicated. Pointers are what Objective-C expects, but pointers are also what Objective-C gives you. Pointers are exactly what you’ve got, so there’s no problem.

For example, one way to concatenate two NSStrings is to call the NSString method stringByAppendingString:, which the documentation tells you is declared as follows:
    - (NSString *)stringByAppendingString:(NSString *)aString

This declaration is telling you (after you allow for the Objective-C syntax) that this method expects one NSString* parameter and returns an NSString*. That sounds messy, but it isn’t, because every NSString is really an NSString*. So nothing could be simpler than to obtain a new NSString consisting of two concatenated NSStrings:
    NSString* s1 = @"Hello, ";
    NSString* s2 = @"World!";
    NSString* s3 = [s1 stringByAppendingString: s2];

Sometimes, however, a function or method expects as a parameter a pointer to a thing, but what you’ve got is not that pointer but the thing itself. Thus, you need a way to create a pointer to that thing. The solution is the address operator (K&R 5.1), which is an ampersand before the name of the thing.
For example, there’s an NSString method for reading from a file into an NSString, which is declared like this:
    + (id)stringWithContentsOfFile:(NSString *)path
                          encoding:(NSStringEncoding)enc
                             error:(NSError **)error	
Never mind for now what an id is, and don’t worry about the Objective-C method declaration syntax. Just consider the types of the parameters. The first one is an NSString*; that’s no problem, as every reference to an NSString is actually a pointer to an NSString. An NSStringEncoding turns out to be merely an alias to a primitive data type, an NSUInteger, so that’s no problem either. But what on earth is an NSError**?
By all logic, it looks like an NSError** should be a pointer to a pointer to an NSError. And that’s exactly what it is. This method is asking to be passed a pointer to a pointer to an NSError. Well, it’s easy to declare a pointer to an NSError:
    NSError* err;
But how can we obtain a pointer to that? With the address operator! So our code might look, schematically, like this:
    NSString* path = // something or other
    NSStringEncoding enc = // something or other
    NSError* err = nil;
    NSString* result =[NSString stringWithContentsOfFile: path encoding: enc error: &err];
The important thing to notice is the ampersand. Because err is a pointer to an NSError, &err is a pointer to a pointer to an NSError, which is just what we’re expected to provide. Thus, everything goes swimmingly.
You can use the address operator to create a pointer to any named variable. A C function is technically a kind of named variable, so you can even create a pointer to a function! This is an example of when you’d use the name of the function without the parentheses: you aren’t calling the function, you’re talking about it. For example, &square is a pointer to the square function. Moreover, just as the bare name of an array is implicitly a pointer to its first element, the bare name of a function is implicitly a pointer to the function; the address operator is optional.

Flow Control and Conditions ( Learn C Programming )


Basic flow control is fairly simple and usually involves a condition in parentheses and a block of conditionally executed code in curly braces. These curly braces constitute a new scope, into which new variables can be introduced. So, for example:
    if (x == 7) {
        int i = 0;
i += 1; }
After the closing curly brace in the fourth line, the i introduced in the second line has ceased to exist, because its scope is the inside of the curly braces. If the contents of the curly braces consist of a single statement, the curly braces can be omitted, but I would advise beginners against this shorthand, as you can confuse yourself. A common be‐ ginner mistake (which will be caught by the compiler) is forgetting the parentheses around the condition. The full set of flow control statements is given, and I’ll just summarize them schematically here (Example 1-1).
Example 1-1. The C flow control constructs
if (condition) { statements;
}
if (condition) { statements;
} else { statements;
}
if (condition) { statements;
} else if (condition) { statements;
} else { statements;


while (condition) { statements;
}
do { statements;
} while (condition);
for (before-all; condition; after-each) { statements;
}

The if...else if...else structure can have as many else if blocks as needed, and the else block is optional. Instead of an extended if...else if...else if...else structure, when the conditions would consist of comparing various values against a single value, you can use the switch statement; be careful, though, as it is rather con‐ fusing and can easily go wrong. The main trick is to re‐ member to end every case with a break statement, unless you want it to “fall through” to the next case (Example 1-2).
Example 1-2. A switch statement
NSString* key;
switch (tag) {
    case 1: { // i.e., if tag is 1
        key = @"lesson";
        break;
    }
    case 2: { // i.e., if tag is 2
        key = @"lessonSection";
break; }
    case 3: { // i.e., if tag is 3
        key = @"lessonSectionPartFirstWord";
        break;
} }
The C for loop needs some elaboration for beginners (Example 1-1). The before-all statement is executed once as the for loop is first encountered and is usually used for initialization of the counter. The condition is then tested, and if true, the block is exe‐ cuted; the condition is usually used to test whether the counter has reached its limit. The after-each statement is then executed, and is usually used to increment or dec‐ rement the counter; the condition is then immediately tested again. Thus, to execute a block using integer values 1, 2, 3, 4, and 5 for i, the notation is:
    int i;
    for (i = 1; i < 6; i++) {
        // ... statements ... 
    }

The need for a counter intended to exist solely within the for loop is so common that C99 permits the declaration of the counter as part of the before-all statement; the declared variable’s scope is then inside the curly braces:
    for (int i = 1; i < 6; i++) {
        // ... statements ...
}
The for loop is one of the few areas in which Objective-C extends C’s flow-control syntax. Certain Objective-C objects, such as NSArray, represent enumerable collections of other objects; “enumerable” basically means that you can cycle through the collection, and cycling through a collection is called enumerating the collection. (I’ll discuss the main enumerable collection types in Chapter 10.) To make enumerating easy, Objective-C provides a for...in operator, which works like a for loop:
    SomeType* oneItem;
    for (oneItem in myCollection) {
        // ... statements ....
    }
On each pass through the loop, the variable oneItem (or whatever you call it) takes on the next value from within the collection. As with the C99 for loop, oneItem can be declared in the for statement, limiting its scope to the curly braces:
    for (SomeType* oneItem in myCollection) {
        // ... statements ....
}
To abort a loop from inside the curly braces, use the break statement. To abort the current iteration from within the curly braces and proceed to the next iteration, use the continue statement. In the case of while and do, continue means to perform imme‐ diately the conditional test; in the case of a for loop, continue means to perform im‐ mediately the after-each statement and then the conditional test.
C also has a goto statement that allows you to jump to a named (labeled) line in your code; even though goto is notoriously “considered harmful,” there are situations in which it is pretty much necessary, especially because C’s flow control is otherwise so primitive. 

   Note It is permissible for a C statement to be compounded of multiple state‐ ments, separated by commas, to be          executed sequentially. The last of the multiple statements is the value of the compound statement as a whole. This construct, for instance, lets you perform some secondary action before each test of a condition or perform more than one after-each action.


We can now turn to the question of what a condition consists of. C has no separate boolean type; a condition either evaluates to 0, in which case it is considered false, or it doesn’t, in which case it is true. Comparisons are performed using the equality and relational operators (K&R 2.6); for example, == compares for equality, and < compares for whether the first operand is less than the second. Logical expressions can be com‐ bined using the logical-and operator (&&) and the logical-or operator (||); using these along with parentheses and the not operator (!) you can form complex conditions. Evaluation of logical-and and logical-or expressions is short-circuited, meaning that if the left condition settles the question, the right condition is never even evaluated.

Warning : Don’t confuse the logical-and operator (&&) and the logical-or opera‐ tor (||) with the bitwise-and operator (&) and the bitwise-or opera‐ tor (|) discussed earlier. Writing & when you mean && (or vice versa) can result in surprising behavior.


The operator for testing basic equality, ==, is not a simple equal sign; forgetting the difference is a common novice mistake. The problem is that such code is legal: simple assignment, which is what the equal sign means, has a value, and any value is legal in a condition. So consider this piece of (nonsense) code:
    int i = 0;
    while (i = 1) {
i = 0; }
You might think that the while condition tests whether i is 1. You might then think: i is 0, so the while body will never be performed. Right? Wrong. The while condition does not test whether i is 1; it assigns 1 to i. The value of that assignment is also 1, so the condition evaluates to 1, which means true. So the while body is performed. Moreover, even though the while body assigns 0 to i, the condition is then evaluated again and assigns 1 to i a second time, which means true yet again. And so on, forever; we’ve written an endless loop, and the program will hang.
C programmers revel in the fact that testing for zero and testing for false are the same thing and use it to create compact conditional expressions, which are considered elegant and idiomatic. Such idioms can be confusing, but one of them is commonly used in Objective-C, namely, in order to test an object reference to see whether it is nil. Since nil is a form of zero, one can ask whether an object s is nil like this:
    if (!s) {
        // ...
}

Objective-C introduces a BOOL type, which you should use if you need to capture or maintain a condition’s value as a variable, along with constants YES and NO (repre‐ senting 1 and 0), which you should use when setting a boolean value. Don’t compare anything against a BOOL, not even YES or NO, because a value like 2 is true in a con‐ dition but is not equal to YES or NO. (Getting this wrong is a common beginner mistake, and can lead to unintended results.) Just use the BOOL directly as a condition, or as part of a complex condition, and all will be well. For example:
    BOOL isnil = (nil == s);
    if (isnil) { // not: if (isnil == YES) 
// ... } 

  

 

Operators


Arithmetic operators are straightforward, but watch out for the rule that “integer division truncates any fractional part.” This rule is the cause of much novice error in C. If you have two integers and you want to divide them in such a way as to get a fractional result, you must represent at least one of them as a float:
    int i = 3;
    float f = i/2; // beware! not 1.5
To get 1.5, you should have written i/2.0 or (float)i/2.
The integer increment and decrement operators , ++ and --, work differently depending on whether they precede or follow their variable. The expression ++i replaces the value of i by 1 more than its current value and then uses the resulting value; the expression i++ uses the current value of i and then replaces it with 1 more than its current value. This is one of C’s coolest features.
C also provides bitwise operators , such as bitwise-and (&) and bitwise-or (|); they operate on the individual binary bits that constitute integers. You are most likely to need bitwise-or, because the Cocoa API often uses bits as switches when multiple options are to be specified simultaneously. For example, when specifying how a UIView is to be animated, you are allowed to pass an options argument whose value comes from the UIViewAnimationOptions enumeration, whose definition begins as follows:
    typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    UIViewAnimationOptionLayoutSubviews
    UIViewAnimationOptionAllowUserInteraction
    UIViewAnimationOptionBeginFromCurrentState
    UIViewAnimationOptionRepeat
    UIViewAnimationOptionAutoreverse
// ... };
= 1 <<  0,
= 1 <<  1,
= 1 <<  2,
= 1 <<  3,
= 1 <<  4,
The << symbol is the left shift operator; the right operand says how many bits to shift the left operand. So pretend that an NSUInteger is 8 bits (it isn’t, but let’s keep things simple and short). Then this enumeration means that the following name–value pairs are defined (using binary notation for the values):
UIViewAnimationOptionLayoutSubviews
    00000001
UIViewAnimationOptionAllowUserInteraction
    00000010
UIViewAnimationOptionBeginFromCurrentState
    00000100
UIViewAnimationOptionRepeat
    00001000
UIViewAnimationOptionAutoreverse
    00010000
The reason for this bit-based representation is that these values can be combined into a single value (a bitmask) that you pass to set the options for this animation. All Cocoa has to do to understand your intentions is to look to see which bits in the value that you pass are set to 1. So, for example, 00011000 would mean that UIViewAnimationOption- Repeat and UIViewAnimationOptionAutoreverse are both true (and that the others, by implication, are all false).
The question is how to form the value 00011000 in order to pass it. You could just do the math, figure out that binary 00011000 is decimal 24, and set the options argument to 24, but that’s not what you’re supposed to do, and it’s not a very good idea, because it’s error-prone and makes your code incomprehensible. Instead, use the bitwise-or operator to combine the desired options:
    (UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse)
This notation works because the bitwise-or operator combines its operands by setting in the result any bits that are set in either of the operands, so 00001000 | 00010000 is 00011000, which is just the value we’re trying to convey. (And how does the runtime parse the bitmask to discover whether a given bit is set? With the bitwise-and operator.)
Simple assignment is by the equal sign. But there are also compound as‐ signment operators that combine assignment with some other operation. For example:
height *= 2; // same as saying: height = height * 2; The ternary operator (?:) is a way of specifying one of two values depending on a
condition. The scheme is as follows:
(condition) ? exp1 : exp2
If the condition is true (see the next section for what that means), the expression exp1 is evaluated and the result is used; otherwise, the expression exp2 is evaluated and the result is used. For example, you might use the ternary operator while performing an assignment, using this schema:
myVariable = (condition) ? exp1 : exp2;
What gets assigned to myVariable depends on the truth value of the condition. There’s nothing happening here that couldn’t be accomplished more verbosely with flow con‐ trol, but the ternary operator can greatly improve clarity, and I use it a lot.

Arrays ( Learn C Programming )


A C array (K&R 5.3) consists of multiple elements of the same data type. An array declaration states the data type of the elements, followed by the name of the array, along with square brackets containing the number of elements:

    int arr[3]; // means: arr is an array consisting of 3 ints

To refer to an element of an array, use the array’s name followed by the element number in square brackets. The first element of an array is numbered 0. So we can initialize an array by assigning values to each element in turn:

    int arr[3];
    arr[0] = 123;
    arr[1] = 456;
    arr[2] = 789;

Alternatively, you can initialize an array at declaration time by assigning a list of values in curly braces, just as with a struct. In this case, the size of the array can be omitted from the declaration, because it is implicit in the initialization (K&R 4.9):
    int arr[] = {123, 456, 789};
Curiously, the name of an array is the name of a pointer (to the first element of the array). Thus, for example, having declared arr as in the preceding examples, you can use arr wherever a value of type int* (a pointer to an int) is expected. This fact is the basis of some highly sophisticated C idioms that you almost certainly won’t need to know about (which is why I don’t recommend that you read any of K&R Chapter 5 beyond section 3).
Here’s an example where a C array might be useful when programming iOS. The func‐ tion CGContextStrokeLineSegments is declared like this:
Arrays in C programming
        Figure 1-1. Pointers and assignment

 void CGContextStrokeLineSegments (
       CGContextRef c,
       const CGPoint points[],
       size_t count
);

The second parameter is a C array of CGPoints. That’s what the square brackets tell you. So to call this function, you’d need to know at least how to make an array of CGPoints. You might do it like this: 

CGPoint arr[] = {{4,5}, {6,7}, {8,9}, {10,11}};
Having done that, you can pass arr as the second argument in a call to CGContextStroke-
LineSegments.
Also, a C string, as I’ve already mentioned, is actually an array. For example, the NSString method stringWithUTF8String: takes (according to the documentation) “a NULL- terminated C array of bytes in UTF8 encoding;” but the parameter is declared not as an array, but as a char*. Those are the same thing, and are both ways of saying that this method takes a C string.
(The colon at the end of the method name stringWithUTF8String: is not a misprint; many Objective-C method names end with a colon. 

Tuesday, December 3, 2013

Structs (Learn C Programming)


C offers few simple native data types, so how are more complex data types made? There are three ways: structures, pointers, and arrays. Both structures and pointers are going to be crucial when you’re programming iOS. C arrays are needed less often, because Objective-C has its own NSArray object type.
A C structure, usually called a struct (K&R 6.1), is a compound data type: it combines multiple data types into a single type, which can be passed around as a single entity.
Moreover, the elements constituting the compound entity have names and can be ac‐ cessed by those names through the compound entity, using dot-notation. The iOS API has many commonly used structs, typically accompanied by convenience functions for working with them.
For example, the iOS documentation tells you that a CGPoint is defined as follows:
    struct CGPoint {
       CGFloat x;
       CGFloat y;
    };
    typedef struct CGPoint CGPoint;
Recall that a CGFloat is basically a float, so this is a compound data type made up of two simple native data types; in effect, a CGPoint has two CGFloat parts, and their names are x and y. (The rather odd-looking last line merely asserts that one can use the term CGPoint instead of the more verbose struct CGPoint.) So we can write:
    CGPoint myPoint;
    myPoint.x = 4.3;
    myPoint.y = 7.1;
Just as we can assign to myPoint.x to set this part of the struct, we can say myPoint.x to get this part of the struct. It’s as if myPoint.x were the name of a variable. Moreover, an element of a struct can itself be a struct, and the dot-notation can be chained. To illustrate, first note the existence of another iOS struct, CGSize:
    struct CGSize {
       CGFloat width;
       CGFloat height;
    };
    typedef struct CGSize CGSize;
Put a CGPoint and a CGSize together and you’ve got a CGRect:
    struct CGRect {
       CGPoint origin;
       CGSize size;
    };
    typedef struct CGRect CGRect;
So suppose we’ve got a CGRect variable called myRect, already initialized. Then myRect.origin is a CGPoint, and myRect.origin.x is a CGFloat. Similarly, myRect.size is a CGSize, and myRect.size.width is a CGFloat. You could change just the width part of our CGRect directly, like this:
    myRect.size.width = 8.6; 
Instead of initializing a struct by assigning to each of its elements, you can initialize it at declaration time by assigning values for all its elements at once, in curly braces and separated by commas, like this:
CGPoint myPoint = { 4.3, 7.1 }; 
    CGRect myRect = { myPoint, {10, 20} };

You don’t have to be assigning to a struct-typed variable to use a struct initializer; you can use an initializer anywhere the given struct type is expected, but you might also have to cast to that struct type in order to explain to the compiler what your curly braces mean, like this:
    CGContextFillRect(con, (CGRect){myPoint, {10, 20}}); 
In that example, CGContextFillRect is a function. I’ll talk about functions later in this chapter, but the upshot of the example is that what comes after the first comma has to be a CGRect, and can therefore be a CGRect initializer provided it is accompanied by a CGRect cast.