• No se han encontrado resultados

Territorio

In document Trabajo Fin de Grado (página 33-41)

3. ANÁLISIS DEL CONTENIDO

3.2. ANÁLISIS COMPARATIVO DE LOS CONTENIDOS

3.2.1. Territorio

This program’s output depends on the target architecture. In our case, the output was 42.0 as an integer -266654968

For this brief introductory section, we will consider that all types in C fall into one of these categories:

• Integer numbers (int, char, …).

• Floating point numbers (double and float).

• Pointer types.

• Composite types: structures and unions.

• Enumerations.

In Chapter 9 we are going to explore the type system in more detail. If you come with a background in a higher-level language, you might find some commonly known items missing from this block. Unfortunately, there are no string and Boolean types in C89. An integer value equal to zero is considered false; any non-zero value is considered truth.

8.3 Control Flow

According to von Neumann principles, the program execution is sequential. Each statement is executed one after another. There are several statements to change control flow.

8.3.1 if

Listing 8-5 shows an if statement with an optional else part. If the condition is satisfied, the first block is executed. If the condition is not satisfied, the second block is executed, but the second block is not mandatory.

Listing 8-5. if_example.c int x = 100;

if (42) {

puts("42 is not equal to zero and thus considered truth");

}

if (x > 3) {

puts("X is greater than 3");

} else {

puts("X is less than 3");

}

The braces are optional. Without braces, only one statement will be considered part of each branch, as shown in Listing 8-6.

Listing 8-6. if_no_braces.c if (x == 0)

puts("X is zero");

else

puts("X is not zero");

Notice that there is a syntax fault, called dangling else. Check Listing 8-7 and see if you can certainly attribute the else branch to the first or the second if. To solve this disambiguation in case of nested ifs, use braces.

Listing 8-7. dangling_else.c

if (x == 0) if (y == 0) { puts("A"); } else { puts("B"); } /* You might have considered one of the following interpretations.

* The compiler can issue a warning to prevent you */

if (x == 0) {

if (y == 0) { printf("A"); } else { puts("B"); }

}

if (x == 0) {

if (y == 0) { puts("A"); } } else { puts("B"); }

8.3.2 while

A while statement is used to make cycles.

Listing 8-8. while_example.c int x = 10;

while ( x != 0 ) { puts("Hello");

x = x - 1;

}

If the condition is satisfied, then the body is executed. Then the condition is checked once again, and if it is satisfied, then the body is executed again, and so on.

An alternative form do ... while ( condition ); allows you to check conditions after executing the loop body, thus guaranteeing at least one iteration. Listing 8-9 shows an example.

Notice that a body can be empty, as follows: while (x == 0);. The semicolon after the parentheses ends this statement.

Listing 8-9. do_while_example.c int x = 10;

do {

printf("Hello\n"); x = x - 1;

}

while ( x != 0 );

8.3.3 for

A for statement is ideal to iterate over finite collections, such as linked lists or arrays. It has the following form: for ( initializer ; condition; step ) body. Listing 8-10 shows an example.

Listing 8-10. for_example.c

int a[] = {1, 2, 3, 4}; /* an array of 4 elements */

int i = 0;

for ( i = 0; i < 4; i++ ) { printf( "%d", a[i]) }

First, the initializer is executed. Then there is a condition check, and if it holds, the loop body is executed, and then the step statement.

In this case, the step statement is an increment operator ++, which modifies a variable by increasing its value by one. After that, the loop begins again by checking the condition, and so on. Listing 8-11 shows two equivalent loops.

Listing 8-11. while_for_equiv.c

The break statement is used to end the cycle prematurely and fall to the next statement in the code.

continue ends the current iteration and starts the next iteration right away. Listing 8-12 shows an example.

Listing 8-12. loop_cont.c

Note also that in the for loop, the initializer, step, or condition expressions can be left empty.

Listing 8-13 shows an example.

A goto statement allows you to make jumps to a label inside the same function. As in assembly, labels can mark any statement, and the syntax is the same: label: statement. This is often described a bad codestyle;

however, it might be quite handy when encoding finite state machines. What you should not do is to abandon well-thought-out conditionals and loops for goto-spaghetti.

The goto statement is sometimes used as a way to break from several nested cycles. However, this is often a symptom of a bad design, because the inner loops can be abstracted away inside a function (thanks to the compiler optimizations, probably for no runtime cost at all). Listing 8-14 shows how to use goto to break out of all inner loops.

Listing 8-14. goto.c int i;

int j;

for (i = 0; i < 100; i++ )

for( j = 0; j < 100; j++ ) {

The goto statement mixed with the imperative style makes analyzing the program behavior harder for both humans and machines (compilers), so the cheesy optimizations the modern compilers are capable of become less likely, and the code becomes harder to maintain. We advocate restricting goto usage to the pieces of code that perform no assignments, like the implementations of finite state machines. This way you won’t have to trace all the possible program execution routes and how the values of certain variables change when the program executes one way or another.

8.3.5 switch

A switch statement is used like multiple nested if’s when the condition is some integer variable being equal to one or another value. Listing 8-15 shows an example.

Listing 8-15. case_example.c

Every case is, in fact, a label. The cases are not limited by anything but an optional break statement to leave the switch block. It allows for some interesting hacks.1 However, a forgotten break is usually a source of bugs. Listing 8-16 shows these two behaviors: first, several labels are attributed to the same case, meaning no matter whether x is 0, 1 or 10, the code executed will be the same. Then, as the break is not ending this case, after executing the first printf the control will fall to the next instruction labeled case 15, another printf.

Listing 8-16. case_magic.c

1One of the most known hacks is called Duff’s device and incorporates a cycle which is defined inside a switch and contains several cases.

/* Notice the absence of `break`! */

Listing 8-17 showcases a program that searches for the first divisor, which is then printed to stdout. The function first_divisor accepts an argument n and searches for an integer r from 1 exclusive to n inclusive, such that n is a multiple of r. If r = n, we have obviously found a prime number.

Notice how the statement after for was not put between curly braces because it is the only statement inside the loop. The same happened with the if body, which consists of a sole return i. You can of course put it inside braces, and some programmers actually encourage it.

Listing 8-17. divisor.c

#include <stdio.h>

int first_divisor( int n ) { int i;

8.3.7 Example: Is It a Fibonacci Number?

Listing 8-18 shows a program that checks whether a number is a Fibonacci number or not. The Fibonacci series is defined recursively as follows:

f1 = 1 f2 = 1 fn = fn−1 + fn−2

This series has a large number of applications, notably in combinatorics. Fibonacci sequences appear even in biological settings, such as branching in trees, arrangement of the leaves on a stem, etc.

The first Fibonacci numbers are 1, 1, 2, 3, 5, 8, etc. As you see, each number is the sum of two previous numbers.

In order to check whether a given number n is contained in a Fibonacci sequence, we adopt a straightforward (not necessarily optimal) approach of calculating all sequence members prior to n. The

nature of a Fibonacci sequence implies that it is ascending, so if we found a member greater than n and still have not enumerated n, we conclude, that n is not in the sequence. The function is_fib accepts an integer n and calculates all elements less or equal to n. If the last element of this sequence is n, then n is a Fibonacci number and it returns 1; otherwise, it returns 0.

Listing 8-18. is_fib.c

#include <stdio.h>

int is_fib( int n ) { int a = 1;

int b = 1;

if ( n == 1 ) return 1;

while ( a <= n && b <= n ) { int t = b;

if (n == a || n == b) return 1;

b = a;

a = t + a;

}

return 0;

}

void check(int n) { printf( "%d -> %d\n", n, is_fib( n ) ); } int main(void) {

int i;

for( i = 1; i < 11; i = i + 1 ) { check( i );

}

return 0;

}

In document Trabajo Fin de Grado (página 33-41)

Documento similar