0% found this document useful (0 votes)
41 views144 pages

C Language With Resolved Exercises

The document provides an introduction to the C programming language, detailing its history, characteristics, and basic syntax through examples. It explains fundamental concepts such as data types, functions, and input/output operations, using simple code snippets to illustrate each point. Additionally, it includes exercises for readers to practice their understanding of the material presented.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views144 pages

C Language With Resolved Exercises

The document provides an introduction to the C programming language, detailing its history, characteristics, and basic syntax through examples. It explains fundamental concepts such as data types, functions, and input/output operations, using simple code snippets to illustrate each point. Additionally, it includes exercises for readers to practice their understanding of the material presented.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 144

LANGUAGES C

With Solved Exercises


2 Introduction to the C Language

1
Introduction

Brief history

The C Language was created in 1972 by Dennis Ritchie on a PDP-11.


Digital Equipment Corporation under the UNIX operating system. It was the result
end of a project that began with a language called BCPL (Basic
Combined Programming Language) designed by Martin Richards in 1967, which to
it was also influenced by the CPL language (Combined Programming Language)
Language) developed by the universities of Cambridge and London. As of
BCPL, Ken Thompson created a language called B, which led to
development of the C Language.

For many years, the standard for C was the one provided with the
version 5 of UNIX. But with the growing popularity of microcomputers
many different implementations appeared (Microsoft's Quick C, Turbo C
from Borland, etc.) that, although they were highly compatible with each other, had some
differences. For this reason, in 1983 a committee was created that drafted the document that
define the ANSI standard of C.

The C Language is a middle-level language, that is to say, without being a language of


high level like COBOL, BASIC or Pascal, nor is it an Assembly Language.

The main characteristics of the C Language are:

It has a complete set of control instructions.


It allows the grouping of instructions.
Include the concept of pointer (a variable that contains the address of another)
variable).
The arguments of the functions are passed by their value. Therefore,
any change in the value of a parameter within a function does not
it affects the value of the variable outside of it.
I/O is not part of the language, but is provided through
a library of functions.
Allows the separation of a program into modules that admit
independent compilation.
1. Introduction 3

Originally, the C Language was closely tied to the UNIX operating system.
which is mostly written in C. Later, it began to be used in
other operating systems for programming editors, compilers, etc. Although it is
known as a systems programming language, it doesn't adapt poorly to the rest
of applications. In fact, today a high percentage of software for
personal computers are written in C Language. For example, the system
MS-DOS operating system.

In this chapter we will take a quick tour of some of the


characteristics of language through some very simple examples. In the
In the following chapters, we will study in much more detail most of the
aspects of the C Language. We will base this study on the implementation of
Borland: Turbo C. These programs can be executed from the environment.
integrated Turbo C or compiling and linking them from the command line of
TWO (Chapter 12).

Example 1: #include, main(), printf()

We'll start with a simple example: a program that displays in


screen a phrase.

/* Example 1. Program DOCENA.C */

#include <stdio.h>

main ()
{
int dozen;

docena = 12;
A dozen is %d units
}

This program displays the phrase 'A dozen is 12'


units." Let's look at the meaning of each line of the program.

/* Example 1. Program DOZEN.C */

It is a comment. The Turbo C compiler ignores everything that is between


the beginning (/*) and end (*/) symbols of a comment. Comments
Delimited by these symbols can span multiple lines.
4 Introduction to the C Language

#include <stdio.h>

It tells Turbo C to include a file in the compilation process.


denominadostdio.h. This file is provided as part of the compiler of
Turbo C contains the necessary information for its proper functioning.
Data I/O.

The #include statement is a C instruction. The symbol # identifies it.


as a directive, that is, an order for the C preprocessor, responsible for
carry out certain tasks prior to compilation.

The *.hse files are called header files. All programs


C require the inclusion of one or more files of this type, so
it is usually necessary to use several lines #include.

main ()

It is the name of a function. A C program consists of one or more


functions, but at least one of them must be called main(), since C programs
they start to be executed by this function.

The parentheses identify amain() as a function. Generally, inside


It includes information that is sent to the function. In this case, there is no
transfer of information so there is nothing written inside. Still, they are
mandatory.

The body of a function (set of statements that compose it) goes


framed between braces {and}. That is the meaning of the braces that appear in the
example.

int dozen;

It is a declarative statement. It indicates that a variable called will be used.


docenaque is of integer type. The word is a keyword in C that
identify one of the basic data types we will study in Chapter 3. In
It is mandatory to declare all variables before they are used. The ';' identifies
the line like a C statement.

dozen = 12;

It is an assignment statement. It stores the value 12 in the variable dozen.


Note that it ends with a semicolon. As in most languages, the
The assignment operator in C is the equal sign "=".
1. Introduction 5

A dozen is %d units

This sentence is important for two reasons: first, it is an example


of calling a function. It also illustrates the use of a standard output function:
the printf() function.

The sentence consists of two parts:

The name of the function: printf().


The arguments. In this case, there are two separated by a comma:
A dozen is %d units
dozen

Like every C statement, it ends with a semicolon.

The printf() function works as follows: the first argument is


a format string. This string will be what will basically be displayed in
screen. In the format string, format codes can appear
escape characters.

A format code starting with the symbol %e indicates the position


within the string where the second argument will be printed, in this case, the
variable document. Later we will study all the format codes of
Turbo C. In this example, %d indicates that a number will be displayed in its place.
decimal integer.

An escape character starts with the symbol\. They are characters that have
a special interpretation. The sequence is the character newline and corresponds to
the sequence LF+CR (line feed + carriage return).

The printf() function belongs to the standard library of C. The definitions


necessary for it to work correctly are found in the archivostdio.h,
there that the statement #include <stdio.h> is necessary.

Example 2: scanf()

The following program performs the conversion from feet to meters using the
equivalence

1 foot = 0.3084 meters

The program asks for the number of feet via keyboard and displays on screen the
corresponding metros.
6 Introduction to the C Language

/* Example 2. Program PIES.C */

#include <stdio.h>

main ()
{
int pies;
float meters;

Feet?:
scanf("%d", &pies);

meters = feet * 0.3084;

%d feet are equivalent to %f meters


}

We will now study the news that appears in this program.

float meters;

It is a declarative statement that indicates that a variable is going to be used.


call meters, which is of the float type. This type of data is used to declare
numeric variables that can have decimals.

Feet?:

It is the printf() function commented on before. This time it only has a


argument: the control chain without format codes. This statement
simply place the cursor at the beginning of the next line ( ) and visualize it
string as it appears in the argument.

scanf ("%d", &pies);

scanf() is a function from the standard library of C (like printf()), that


allows reading data from the keyboard and storing it in a variable. In the example, the
the first argument, %d, tells ascanf() to take an integer number from the keyboard.
The second argument, &pies, indicates in which variable the read data will be stored.
The symbol & before the variable name is necessary for scanf()
It works correctly. We will clarify this detail in later chapters.

pies * 0.3084;

The result of multiplying the variable feet is stored in the variable meters.
0.3084. The symbol * is the operator used by C for multiplication.
1. Introduction 7

%d feet are equivalent to %f meters

Here printf() has 3 arguments. The first is the control string, with
two format codes: %dy%f. This implies that printf() requires two
additional arguments. These arguments fit in order, from left to
right, with the format codes. %d is used for the variable feet and %f for the
variable meters

%dpies are equivalent to %fmeters

The code is used to represent variables of the float type.

Example 3: Functions with arguments

We will now see two examples of programs that use created functions.
by the programmer. A function is a subroutine that contains one or more
C statements. It is defined by a name, followed by two parentheses () between the
There may or may not be arguments. The arguments are values that are passed to the
function when called.

Let's see, first of all, an example of a function with no arguments.

/* Example 3.1 - Program FUNCTION1.C */

#include <stdio.h>

main()
{
This message is displayed by the main() function
MyFunction();
}

/* Definition of the function MyFunction() */


MyFunction()
{
This other one is shown by MyFunction()
}
8 Introduction to the C Language

In this example, the function MyFunction() is used to display on the screen.


a phrase. As it appears, MyFunction() is invoked just like printf() or scanf(), it is
to say, you simply write the name of the function and the parentheses. The
The definition of MyFunction() looks the same as main(): the name of the
function with parentheses and, subsequently, the body of the function enclosed in
keys.

The following example illustrates the use of a function with arguments. The
the program visualizes the square of an integer through a function that
receives that number as an argument.

/* Example 3.2 - Program FUNCTION2.C */

#include <stdio.h>

main ()
{
int num;

Type an integer number:


scanf("%d", &num);
square (num);
}

/* Definition of the square() function */


square (int x)
{
The square of %d is %d
}

square (int x)

It is the declaration of the function square(). Inside the parentheses, you put
the variable that will receive the value passed to square() and what type it is. Thus, if it
type the value 6, it is stored in num when calling cuadrado(num), the
variable number copies into variable x, which is the one used internally
squareFunction()

It is important to keep two terms clear:

1. The term ARGUMENT refers to the variable used when calling the
function.
2. The term FORMAL PARAMETER refers to the variable of a
function that receives the value of the arguments.

It is also important to be clear that the copying of variables is done only in


an address: from the argument to the formal parameter. Any modification of
the formal parameter made within the function has no influence on the
argument.
1. Introduction 9

... ARGUMENT
...
square (num)
...
...
When calling the function cuadrado(), the ARGUMENT num is
copy in the FORMAL PARAMETER x.

Square (int x)
{ PARAMETER
printf (... ); FORMAL
}

Another detail to keep in mind is the type of argument that is used for
calling a function must be the same as the formal parameter it receives
value. Thus, the square function should not be called with a float type argument.
(later we will see that C allows for some flexibility in this aspect).

Example 4: Functions that return values

To conclude the chapter, we will see an example that uses a function that
returns a value. The following program reads two integers from the keyboard and
shows its product on screen. For the calculation, a function is used that receives the
two numbers and returns the product of both.

/* Example 4 - MULT.C Program */

#include <stdio.h>

main ()
{
int a, b, product;

Type two integer numbers:


scanf ("%d %d", &a, &b);

product = multiply(a, b);

The result is %d
}

/* Definition of the function multiply() */


multiply (int x, int y)
{
return (x * y);
}
10 Introduction to the C Language

The updates presented in this program are discussed below.

scanf("%d %d", &a, &b);

The control string of descanf() contains two format codes. Just like
what happens in printf(), two more arguments are required, one for each code of
format. The two numbers are typed separated by spaces,
tabs or the Enter key.

return (x * y);

The word 'return' is used within functions to exit them.


returning a value. The returned value by means of returns the one that assumes the
function. This allows for statements like

product = multiply(a, b);

that is, statements in which the function is to the right of the operator
assignment. For our current purposes we can say (although this is not
exactly) that after the return statement the function multiply() acts as if
it was a variable that stores the returned value.

Parentheses are optional; they are included only for clarification.


expression that accompanies a return. They should not be confused with the parentheses of the
functions.

Exercises

1. Find all the errors in the following C program:

include studio.h

/* Program that says how many days are in a week /*

main {}
(
int d

d := 7;
There are days in a week
1. Introduction 11

2. Indicate what the output would be for each of the following groups of statements:

Chronicles of cronopios and famas.


Author: Julio Cortázar

How many lines does this take?

printf ("We are \nlearning /nprogramming in C");

d) int num;
num = 2;
printf ("%d + %d = %d", num, num, num + num);

3.Write a program that calculates the area of a circle with radius R and the
length of its circumference. Request the value of R from the keyboard, showing
on the screen the necessary messages (S = R2; L = 2 R).

4. Two squares with sides L1 and L2 inscribed in each other. Calculate the area.
from the area between both, using a function (which is
squareArea) that returns the area of a square whose side is
pass as an argument.

2.
Elements of a
C program

Introduction

Basically, C is composed of the following elements

Constants
Identifiers
Reserved words
Comments
Operators
12 Introduction to the C Language

To represent these elements, the usual characters (letters, numbers, signs) are used.
punctuation, underlines, ...) although not all elements can use all these characters.

An important feature of the C Language is that in all the previously mentioned elements
Enumerated distinguishes uppercase and lowercase letters. Thus, it is a reserved word of the language.
that is used to declare integer variables, while Int could be the name of a variable.

Constants

The constants that can be used in C are classified in the following way:

Enteras
Reals
Of character

Integer constants

They are numbers without a fractional part. They can be expressed in decimal, octal, or hexadecimal.

An octal constant must start with a zero:

016 16 octal = 14 decimal

Ahexadecimal constant must start with a zero followed by x.

0xA3 A3 hex = 163 decimal

This constant can also be written in any of the following 3 ways:

0XA3 0xa3 0xA3

Integer constants are considered positive unless preceded by the minus sign.
(-):

-150 -063 -0xA

Real Constants

They are also called floating-point constants. They have the following format:

[whole part] [.fractional part] [exponent of 10]

Any of the 3 parts is optional, but if there is no whole part, there must be a fractional part and
vice versa. The exponent of 10 has the format

exponent

the exponent can be a positive or negative number. Valid constants are:


1. Introduction 13

13.21 21.37E1 0.230001 32e2 -81e-8 -.39 -.39E-7

Character constants

They can be of 2 types:

Simple
Character chains

Simple: They are composed of a single character and are enclosed in single quotes. For
example:

a A 9

Non-printable ASCII characters are defined by the backslash ( ) according to the table that
is shown below. It also shows the representation of the backslash characters,
single quotes and double quotes, which have a special treatment in C.

Error! Marker BAR CHARACTER MEANING


no
defined.CODE
ASCII

7 Alarm (Beep)
8 Rollback (BS)
9 Horizontal Tabulator (HT)
10 \n New Line (LF)
11 \v Vertical Tab (VT)
12 New Page (FF)
13 \r Return
34 \" Double quotes
39 \' Simple comma
92 \\ Backslash

ASCII characters can also be represented by their octal or hexadecimal code.


using the format:

octal number or well hexadecimal

what they represent, respectively, the character whoseASCII code is octal number hexadecimal number. Thus,
The letterAcan be represented in any of the three ways indicated below:

A A A

The ' ' character is not valid. Any other character after is interpreted literally. Thus, N is interpreted.
like the letter N.
14 Introduction to the C Language

Strings: They are sequences of simple characters enclosed in double quotes. To the strings
The compiler adds a null character ('\0') as a terminator to characters, and stores them as a
character matrix. Thus, the string "Hola" is composed of the 5 characters 'H', 'o', 'l', 'a', '\0'.

Identifiers

They are the names given to variables, functions, labels or other objects defined by the
programmer.An identifier can be made up of:

Letters (uppercase or lowercase)


Numbers
Underline character

with the condition that the first character is not a number. In certain cases, which will be studied
In Chapter 9, a data identifier may include the dot.

Examples of valid identifiers are:

Selling Price
Num1
_123
D_i_5

Theyarenotvalid:

Selling Price It has a blank space


1Num Start with a number
Selling Price It has a script

Only the first 32 characters of an identifier are significant.

Reserved words

They are special words that cannot be used to name other elements of language. In the
In the previous chapter, we saw some of them, such as int and float. The number of reserved words in C is
significantly lower than that of other languages. In Turbo C there are 43, a few more in Turbo C++ and
Less inANSI C. Throughout the rest of the chapters, they will be revealed.

It is important to insist that C makes a distinction between uppercase and lowercase letters. Therefore, the
The reserved word for cannot be written as FOR, as the compiler does not recognize it as one.
instruction, but interprets it as a variable name.
1. Introduction 15

Comments

As seen in the previous chapter, the compiler recognizes any group as a comment.
of characters located between /* and */, even if they are on different lines. For example,

/* This is a comment that


occupies more than one line */

These comments can be nested in Turbo C++, although it is not advisable to allow the
code compatibility.

Single-line comments can be defined using //.

// This comment takes up a single line

In the case of single-line comments, there is no end-of-comment indicator.

Operators, expressions, statements

An operator is a symbol that indicates some operation on one or more objects of the language.
to those referred to as operands.

Based on the number of operands on which an operator acts, they are classified into:

Unary: they operate on a single operand


Binaries: " " 2 operands
Ternary: " " 3 "

Depending on the type of operation they perform, they are classified into:

Arithmetic
Relational
Logical
Bit treatment
Specials

We will study most of them in this chapter. We will review the rest as we go.
they need.

Operators, along with operands, form expressions. In an expression, the operands


they can be constants, variables, or function calls that return values (like the function
multiply () that appears on page 8).

An expression becomes a sentence when it is followed by a semicolon. When a


a group of statements enclosed in braces { } forms a block, syntactically equivalent to a
sentence.
16 Introduction to C Language

Arithmetic operators

The arithmetic operators are shown in the following table:

OPERATOR DESCRIPTION

UNARY - Change of sign


-- Decrement
++ Increase
BINARY - Stay
+ Sum
* Product
/ Division
% Remaining of integer division

The operators -, + and * work the same way as in the rest of the languages.
programming.

The value returned by the / operator depends on the type of the operands. If they are integers,
returns the integer part of the quotient; if any of them is real, it returns the result as a real number.
The % operator is equivalent to the mod operator in Pascal or Quick-BASIC. It provides the remainder of the
integer division of the operands, which must be integers. For example, given the statements

int x, y;

x=9;
y=2;

the operation x / y returns the value 4, while the operation x % y returns 1. However,
after the sentences

float x;
int y;

x = 9.0;
y=2;

the operation x / y returns 4.5, and in this case, the operator % cannot be applied since one of
the operands are not integer.

The ++ and -- operators increase or decrease the operand by one, respectively.


about whom they act. Thus, the expressions

x++ x- -;

they produce the same effect on the variable x as

x = x + 1; x = x - 1;
1. Introduction 17

and the same that

++x; --x;

It is important to take into account the position of the ++ and -- operators when they are found inside.
from a more complex expression. If the operator is before the variable, the increment operation or
decrement is performed before using the variable's value. If the operator is afterwards, the value is used first.
value of the variable y is then incremented or decremented. To clarify this,
let's take an example.After the sentences

x = 10;
y = ++x;

the values stored in the variables x and y are, in both cases, 11. Since the operator is
before variablex, it is first incremented (assuming the value 11), and then the value is assigned
leave the variable. However, after the statements

x = 10;
y = x++;

The values for x will be, respectively, 11 and 10. In this case, since the operator is after.
from the variable x, first the value of it (10) is used and assigned to y; then the operation is carried out
increment, passing to store the value 11.

Relational operators

They are used to express conditions and describe a relationship between two values. On the page
The following shows a table with all of them.

These operators are used in statements of the type


if (a == b) printf("They are equal");

it should read 'if the content of variable a is equal to that of variable b, display the phrase on screen'
They are the same.
The result of a relational expression can only be true or false, which in C is
identify with the values different from zero and zero, respectively. In the previous statement, the expression
a == b will evaluate as 0 if they are different, and as not 0 if they are equal.

OPERATOR DESCRIPTION

BINARIES > Greater than

>= Greater than or equal to

< Less than


<= Less than or equal to

== Just like
!= Different than

Logical operators
18 Introduction to the C Language

They act on boolean expressions, that is, on true or false values generated by
expressions like those explained in the previous case. They are the following:

OPERATOR DESCRIPTION

UNARY ! not

BINARIES && and


|| or

The result of a logical operation is given by its truth table. The truth table of
the operators !, && and || are shown below:

E b !a a && b a || b
rro
r!
M
arc
ad
or
no
def
this
do.
a

F F V F F
F V V F V
V F F F V
V V F V V

Since the language interprets the value 0 as false and any value other than that as true
zero, arithmetic operators can be used in logical and comparison expressions. By
example, six, yyz store, respectively, the values 20, 4, and 5, the following expressions are
valid:

x == y It is interpreted as FALSE (0)


x=y It is interpreted as TRUE (4)1
x == (y * z) It is interpreted as TRUE (1)

Bit treatment operators

C incorporates certain bit operations typical of Assembly Language, such as


shifts or individual bit manipulation. The operators that perform these operations are
the following:

1
We will see later that the operator = returns the assigned value. In this case, the expression .x = y returns the value 4.
that is evaluated as true.
1. Introduction 19

OPERATOR DESCRIPTION

UNARY ~ not

BINARIES & and


| or
^ or exclusive
>> shift to the right
<< left shift

The operators &(and), |(or), and ~(not) are governed by the same truth table that governs the
Equivalent logical operators (&&, |, !). The difference between the former and the latter is that &, |, and ~
theyoperateatthelevelofindividualbitsandnotoncompletevalueslike&&,| and!.Thus,ifthevariablesaand
respectively, the values

a 0xA1B2
b 0xF0F0

the following expressions are evaluated as follows:

a && b 1 (True) a & b 0xA0B0


a || b 1 (True) a | b 0xF1F2
!a 0 (False) ~a 0x5E4D

The operators &, |, and ~ are identical, respectively, to the instructions of the Language
AssemblerAND, OR and NOT. Therefore, the operator allows setting certain bits to 0 while leaving the rest unchanged.
how they were, the operator|allows setting certain bits to 1 while leaving the rest unchanged, and the operator~
change the bits 1 to 0 and vice versa (See exercise 10 at the end of the chapter).

The exclusive OR operator is identical to the XOR instruction in Assembly Language. Its
The truth table is as follows.

a b a raised to the power of b

F F F
F V V
V F V
V V F

For example, they store the values

a 0xA1B2
b 0x1234

the following expression produces the indicated result

a raised to the power of b 0xB386


20 Introduction to the C Language

The operator allows changing certain bits to their opposite value, leaving the rest unchanged.
modify (See exercise 10 at the end of the chapter).

The shift operators >> and << move all the bits of a variable to the
to the right or to the left, respectively, a determined number of positions. The format
general is

variable << n or well variable >> n

Thus, the sentence

a = b shifted left by 4;

It stores in the content deb, after performing a 4-bit left shift.


content remains unchanged.

Just like inAssembly language, C distinguishes between arithmetic and logical shifts:

Arithmetic shifts: They are performed on integer data and maintain the sign.
Logical shifts: They are performed on data declared as unsigned.2y
just add zeros.

Let's see an example. Suppose a variable declared as an integer (signed), which stores the value
hexadecimalA1B2

a 0xA1B2

a = a << 4 produce 0x1B20


a = a >> 4 produce 0xFA1B

However, if it is declared as unsigned,

a = a << 4 produce 0x1B20


a = a >> 4 produce 0x0A1B

Assignment operators

Assignments are made using the operator =. The use of this operator has certain
aspects that distinguish it from other languages. Firstly, any number can be used
sometimes in an expression. Thus, we can have statements like

a = b = c = 3;

which assigns the value 3 to the variables a, b, and c. This is the case because the assignment operation, in addition to
assign the value, returns the assigned value. Thus, the expression c = 3 returns the value 3, which is assigned to
b, and so on. Statements such as are also possible

x = 3;
y = x + (z = 6);

which assigns ax, y, and z the values 3, 9, and 6, respectively.

2
unsigned is a reserved word that can be applied to the int data type. Variables declared this way are always understood
as positive.
1. Introduction 21

The assignment operator is combined with the operators *, /, %, +, -, <<, >>, &, |, ^ to
cumulative operations. For example,

m *= 5; m = m * 5;
m += b; m = m + b;
m += y - 3; is equivalent to m = m + y - 3;
m - = (y = 5); m = m - (y = 5);
m >>= (2 * x + 1); m = m >> (2 * x + 1);

Conditional operator (?:)

It is a ternary operator that is used to replace simple statements of the type if...else. The
the format of this operator is:

condition

It works as follows: first, the <condition> is evaluated; if it is true, then it is evaluated


<expression_yes>, otherwise <expression_no> is evaluated. For example, in the statement

(x > 9 ? 100 : 200)

the variable takes the value 100 when x > 9, and 200 otherwise.

Pointer operators (&, *)

These operators, unfortunately, are identified with the same symbol as AND.
bit manipulation and the product, respectively. In any case, there is no possibility of
confusion, as they act in different contexts.

OPERATOR DESCRIPTION

UNARIES & Direction of


* Content of

The operator acts on a variable and returns its memory address.After

dir_a = &a;

the variable dir_a stores the address of a.

The operator acts on variables that contain addresses (pointers) and returns the
content of the memory position stored in the variable on which they act. Sidir_aes is a
variable that stores a memory address, the expression

b = *dir_a;

store in the variable the content of the memory position pointed to by dir_a. Likewise,
the expression
22 Introduction to the C Language

*dir_a = 80;

Store the value 80 in the memory address pointed to by dir_a.3

After the following sequence, the variables myz store the values 4 and 2.
respectively.

m = 1;
n = 2;
direcc = &m; (address address of m)
*direcc = 4; (m 4)
direcc = &n; (address address of n)
z = *direction; (z 2)

Size operator (sizeof)


It is a unary operator that returns the size in bytes of the operand. The syntax is:

size of (m)

and returns the values 1, 2, and 4 as char, integer, or float, respectively. Simes a
matrix returns the size, in bytes, occupied by it. It also returns the size of certain objects
of C, called structures, which will be studied in Chapter 8.

Sequential operator (,)


It is used to concatenate expressions. The left side of the comma is evaluated first. For
example, after the expression

x = ( y = 45, y++, y * 2);

the variables x and y store the values 92 and 46, respectively.

Operators . and ->

They will be studied in detail in Chapter 8, dedicated to joints and structures.

Molding operator (cast)

Allows changing the type of an expression. The syntax is:

(type) expression

dondetipoes one of the basic data types that we will study in the next chapter (in the previous one
They have already seen it. For example, in the sequence

int x;
x = 5;

3
For the sentences in which the variable dir_afuncion intervenes to work correctly, it must be declared in a certain way.
special, which we will explain in Chapter 7, in which pointers will be studied.
1. Introduction 23

y = x / 2;

the value assigned to the variable y will be 2, since it performs an integer division. If it is desired that y has a part
fractional, the molding operator will be used:

int x;
x = 5;
y = (float) x / 2;

Now, the variable stores the value 2.5.

In any case, we must be careful with this operator. In the sequence

int x;
x = 5;
y = (float) (x / 2);

the value 2.5 is not assigned, but 2, since the parentheses that wrap the expression x / 2 make that
first perform the integer division and then convert it to float.

Operators [ ] and ( )
Brackets are used to access elements of an array. They will be studied in the
Chapter 7.

Parentheses serve to clarify an expression or to modify the rules of priority between


operators. These priority rules are reflected in the table on the next page.

The priorities of this table can be altered through parentheses. When any
Expressions enclosed in parentheses are evaluated first. If there is nesting, the innermost expressions are evaluated first.
more internal. For example, the expression

x+5*y

is evaluated as follows:

1. 5 * y is calculated first, since the * operator has higher priority than the + operator.
2. Axel adds the result of the previous operation.

However, if we write

(x + 5) * y

Parentheses modify the priority, first evaluating the expression x + 5, and then multiplying.
this value pory.

When an expression involves operators with the same level of priority, they are evaluated in
the direction indicated in the first column of the table.

Assessment to equal Level of Operators


priority level priority

1st ( ) [ ] . ->
24 Introduction to the C Language

2nd ! ~ ++ -- (cast) *4&5sizeof


3rd * / %

4th + -

5th << >>

6th < <= > >=


7th == !=

8th &

9th ^

10th |

11th &&

12º ||

13th ?:

14º assignment operators

15º ,

Lateral effect

When the same operand is used more than once in an expression, and in some of them...
modifying its value may lead to side effect errors. For example, let the sequence

i = 2;
matrix[i] = x + (i = 4);

In the second statement, the element matrix[i] refers to the i-th element of a vector called
matrix. However, that expression does not ensure that the result is stored in matrix[2] or in
matrix[4].

To avoid this kind of problems it is necessary to follow the following rules:

Do not use ++ or -- operators on variables that are used more than once in a
expression.
Do not use ++ or -- operators on variables that are used more than once as
argument of a function.

The directives #include and #define

4
Content operator of.
5
Operator address of.
1. Introduction 25

We will now study two directives that are used in practically all C programs.

Indicate to the compiler to include a source file. The format is

#include "file_name"

or well,

#include <file_name>

siendonom_fichun is a valid DOS file name.

It can be said that when the compiler encounters a line #include, it replaces that line.
by the file non_file.

The use of double quotes "" or angle brackets < > affects where the file nom_fich will be searched.
the first case is sought in the following order:

Directory being worked on.


2. Directories specified when compiling the program from the DOS command line.
3. Directories indicated in the Turbo C implementation.

In the second case, the search order is as follows:

Directory defined with the -I option of the compiler.


2. Directory indicated in the Main Menu of Turbo C.
3. Directories defined in the Turbo C implementation.

In both cases, it is assumed that the file name is not accompanied by any path.
of directory. In case the file name includes a path, it will only be searched in that
directory. Thus, in the case

#include "C:\MIDIR\MIFICH.H"

orwell

#include <C:\MIDIR\MIFICH.H>

the search is only performed in the directory C:\MIDIR, with an error message produced if not
find the file.

The #include directive is mainly used for the inclusion of the so-called files of
Header. The inclusion of these files is necessary when using library functions.
These functions use their own data types and variables that are defined in those files. For example,
the header file required by the functions printf() and scanf() (along with many others) is
llamastdio.h, and therefore whenever a program uses those functions it must include a line like

#include <stdio.h>

In any case, it can be used to include any source file.


26 Introduction to the C Language

#define
In its simplest form, it is used to associate a string of characters with an identifier.
it will replace each time the compiler finds it in the program. The identifier is referred to as
the process of replacing the identifier with the string of characters is called substitution
macro. The general format for this directive is

#define macro chain

Forexample,in

define TRUE 1
#define FALSE 0

when the compiler finds the name of macroTRUEit replaces it with value1. When
find the nameFALSEjust replace it with the value0. It is also valid

#define MESSAGE I/O Error


...
...
printf (MESSAGE);
what is equivalent to the sentence

Input/output error

The substitution process of macros does not occur in the case

MESSAGE

that displays the string of characters MESSAGE on screen. Statements can also be written
as

#define KEY Press any key...


...
...
KEY
Once a macro is defined, it can be used in the definition of subsequent macros:

#define A 1
#define B 2
#define TRES A + B

If the definition of the macro is too long, it is indicated by a backslash and


continue the definition in the next line.

#define LONG This message is


too long

By convention, macro names are written in uppercase.

Exercises
1. Representa de 3 maneras diferentes el carácter nueva línea.
1. Introduction 27

2. Indicate the meaning of each of the following elements

12 012 0x12 0X12


\N ' ' h) '\034'

3. Indicate which of the following identifiers are not correct and why.

accountant b) ACCOUNTANT hello hello


days2 2 days Total_Sum h) Sum-Total

4. Sean x, y, z, u, v, t, variables that contain, respectively, the values 2, 3, 4, 5, 6, and 7, what


Will they be stored after executing the following statements?

x++;
y = ++z;
t = - -v;
v = x + (y multiplied by 3) / 2;

u = x + y / 2;

5. What is the difference between '\a' and '\A'?And between 'A' and 'A'?

6. Indicate which of the following expressions are true and which are false, assuming x, y, z
yt store the values 20, 10, 5, and 2, respectively.

a)x > y && z > t b)x < y && z > t c)x < y || z > t
d)!0 e)!1 f) 0 != 1
g)0 != !1 h)0 == !1 200 || x
j)x * 0 k)x * y l)!!0
m)!(0 == 0) 10 > 5 && !(10 < 9) || 3 <= 4
ñ)1 && !0 || 1 o)1 && !(0 || 1)

7. Seaxuna integer variable that stores the value 10. What will it store after the following?
sentences?

a)y = (x > 9 ? ++x : --x);


b)y = (x > 9 ? x++ : x--);

And does it store the value?

8. A temperature in degrees Celsius C can be converted to its equivalent value in the


Fahrenheit scale according to the following formula:

F = (9 / 5) C + 32

Write a C program that asks for a temperature in degrees Celsius from the keyboard and
display on screen the equivalent temperature in Fahrenheit. (PAYATTENTION to the division 9/5).
28 Introduction to the C Language

9. Write a program that reads an integer hexadecimal number from the keyboard (format code
%x), exchange the high and low bytes, and present the result in hexadecimal on the screen.
(NOTE: Declare the variable that will store the hexadecimal value as an unsigned int and use it)
the operators <<and>>.

10. Write a program that reads a hexadecimal number from the keyboard and manipulates its bits accordingly.
to the following criterion:

Set bits 0, 3, 6, and 9 to 0.


Set bits 2, 5, 8, and 11 to 1.
Change the status of the rest.

Display the result in hexadecimal on the screen. (NOTE: Declare the variable that will store it)
the hexadecimal value as an unsigned int and uses bit manipulation operators.

11. Write a program that reads two integers from the keyboard and displays on the screen their triple.
the difference between the largest and the smallest. (To find out which is the largest, use the operator?:)

12.Write a program that captures a 4-digit integer from the keyboard and rounds it to the
nearest hundred, displaying the result on screen.

3 Basic Types of Data


Basic data types

In C, it is necessary to declare all variables before they are used. When declaring a variable
we must assign one of the 5 basic data types. These basic types are the ones shown in the
next table.

Error! Undefined marker. TYPE WORD SIZE IN BYTES


RESERVED
without value void 0
character character 1
whole int 2
floating point (simple precision) float 4
floating point (double precision) double 8

Every variable declared of one of the previous types (salvovoid) is supposed to be


positive or negative unless one of the modifiers we will see later is applied.
1. Introduction 29

The void type is used to define functions that do not return any value (they have no statement
return). For example, none of the main() functions used so far return values. This
causes a 'Warning' during compilation, which can be avoided by writing void main() instead of writing
simply tomorrow(). Moreover, the void type is used in certain pointer operations that will be studied.
in Chapter 7.

Character type variables are used to store single characters or integers.


byte size. When a single character is assigned to a variable of type char, its code is stored
ASCII. This allows performing mathematical operations with this type of variables. For example, the following
program

Error! Marker not defined.#include <stdio.h>

void main ()
{
charcharacter;

$
character*=2;

printf("%c%d",character,character);
}

Display on screen H 72, since the assignment of the character '$' to the variable character stores in
the variable is itsASCII code (36). The %ces is the format code to display simple characters.

The int type is used to declare variables that will store integers, without decimals.

The float and double types allow storing numbers with decimals.

How to declare variables

AC statement that declares variables must follow the following syntax:

[storage class][modifier] type variable[, variable, ...];

The storage classes and type modifiers will be studied in the following sections.
of the chapter.

Valid examples of variable declaration are:

char letter1, letter2;


int m, n;
float p, q;
double z;

These statements must be placed at the beginning of the function and before any instruction or
function call. They can be preceded by any of the type modifiers that we will study.
continuation.
30 Introduction to the C Language

Type modifiers of a variable

A type modifier is a reserved word that precedes the definition of the type of the
variable, and allows changing the size, range, and the sign/signed characteristic. The modifiers of
type are:

short
long
signed
unsigned

These modifiers apply only to the types char and int, except for long, which in one case can be...
apply to the double type.

The table below shows the ranges and sizes of each type, as they apply to the
modifiers.

Type Modifiers Range Occupy

character unsigned 0 to 255 1 byte


signed -128 to 127 1 byte

int short unsigned 0 to 65,535 2 bytes


signed -32.768 to 32.767 2 bytes

long unsigned 0 to 4,294,967,295 4 bytes


signed -2,147,483,648 to 2,147,483,647 4 bytes

float ±3.4*10-38a ±3.4*10+38 4 bytes

double ±1.7*10-308a ±1.7*10+308 8 bytes


long ±3.4*10-4932a ±1.1*10+4932 10 bytes

Regarding these modifiers, the following aspects must be taken into account:

a) The modifier 'signed' is not necessary. All integer variables, by default, are
consider with a sign.

signed char isequivalentto char


signed int " int

b) The data type char is not affected by the modifiers short or long.

shortcharacter equates to long char and to char

c) Turbo C allows a shorthand notation to declare integers without using the reserved word int.

unsigned is equivalent to unsigned int


1. Introduction 31

short " short int


long " long int
unsignedshort " unsigned short int
unsignedlong " unsigned long int

d) The modified signed and unsigned cause an error if applied to the float types
double.

e) The modifiers short or long do not affect afloat.

f) The double type is affected by the short modifier. The long modifier can be applied to
starting from version 2.00 of Turbo C.

g) The precision that can be obtained for real data types is given by the following
table:

TYPE PRECISION

float 7 digits
double 15 digits
long double 19 digits

Local variables and global variables

Depending on where in the program a variable is declared, it is called local.


global. A variable can be declared in 4 different places in a program:

Outside of all functions (global)


Inside a function (local to the function)
Inside a block framed by braces { } (local block)
As a formal parameter (localizes the function)

A global variable is known throughout the program, while a local variable is only
known by the function or block where it is defined.

Global variables

When a variable is declared outside of all functions, even outside of main(), it


denominaGLOBALy is known for all the functions of the program.

Local variables

Avariable is LOCALLYwhen it is declared:

inside a function
32 Introduction to the C Language

as an argument of a function
in a block of statements framed by { }

In any of these cases, the variable is only known by the function or block where it is.
defined. It is created when entering the function or block and destroyed upon exit. This allows for two variables
Locales for different functions can have the same identifier, but they are considered two variables.
different. For clarity, it is not recommended to use the same names for different variables.

The following is a program intended to illustrate the differences between variables.


local and global. In it, a global variable is declared, known to all parts of the program, and
several local variables, all with the same name: one local to main(), another local to a block within
tomorrow(), and another local to a function.

Error! Marker not defined.#include <stdio.h>


int y; /* Global. Known by both main() and MyFunction() */

main ()
{
int x; /*This x is local to main () */
y=100;
x=1;
printf ("x=%d, y=%d", x, y) /*Visualize x=1, y=100 */
{ /*Startblock*/
int x; /*Thisxislocaltotheblock*/
x=2;
printf ("x=%d, y=%d", x, y) /*Visualize x=2, y=100 */
MyFunction() /*Visualize x=3, y=100 */
printf ("x=%d, y=%d", x, y) /*Visualize x=2, y=100 */
} /*Endofblock*/
printf ("x=%d, y=%d", x, y) /*Visualize x=1, y=100 */
}

MyFunction ()
{
int x; /* Local to MyFunction() */
x=3;
printf("x=%d, y=%d", x, y) /*Visualize x=3, y=100 */
}

Storage classes

There are four types of storage, identified by the reserved keywords:

car
external
static
register

that precede the data type in the declaration of variables.

The storage mode of a variable determines

Which parts of the program do you know (scope)?


how long it remains in memory (lifetime)
1. Introduction 33

Automatic variables (auto)

A variable is class-autonomous if it is local to a function or block. The variable is created when it


calls the function and is destroyed upon exiting it.

The auto specifier is redundant, as all local variables are automatic.


defect.

...
Function ( ...
{
auto int a; /* Declare the variable as local to Function */
...

External variables (extern)

When a variable is defined outside a function, it is classified as external and has scope.
global.

A global variable can be re-declared within the body of a function, adding the
reserved word extern.

...
int a; /* Global variable */

main ()
{
extern int a; It's the same variable
...

This redeclaration is unnecessary when all functions are in the same module. Without
embargo, if a program consists of several different modules, the extern keyword is necessary so that
It is recognized by different modules than the one that contains the variable declaration.

For example, let's suppose that PROG1.C and PROG2.C are two modules that are compiled.
separately and, subsequently, they are linked together to form a single executable module.

Error! Undefined marker. PROG1.C PROG2.C

#include <stdio.h> #include <stdio.h>


int x; extern int x, y;
int y;
ExternalFunction()
main () {
{ printf ("x=%d, y=%d", x, y);
x=10;y=20; }
printf ("x=%d, y=%d", x, y);
InternalFunction();
34 Introduction to the C Language

ExternalFunction();
}

InternalFunction()
{
printf ("x=%d, y=%d", x, y);
}

In the module PROG1.C (which will be compiled to PROG1.OBJ) there is a call to


InternalFunction(). This function does not need redeclaration as it resides in the same
module in which these variables are declared as global. However, there is a call to
ExternalFunction(), and this function resides in a different module (PROG2.C) that will be compiled by
separated (in PROG2.OBJ). So that FuncionExterna() can recognize the variables x and y that are
declared as global in PROG1.C, it is necessary to redeclare them as external class. In case
On the contrary, PROG2.C would "believe" that they are undeclared local variables, so there would be an issue.
a compilation error.

From the object modules PROG1.OBJ and PROG2.OBJ, a linker creates a


executable module, for example PROG.EXE. This program would display the line 3 times

x=10, y=20

Since for the three functions - main(), FuncionInterna() and FuncionExterna() - the variables x and y
they are the same.

Static variables

Astatic variable exists for the entire runtime of the program.

If the static class is applied to a local variable, Turbo C creates permanent storage.
for her, as if it were global. The difference between a static local variable and a global variable is
that the first is only known by the function or block in which it is declared. It can be said that a
static local variable is a local variable that retains its value between calls.

For example, every time the function is called

increment()
{
int n;

n++;
n=%d
}

visualize=16while if the function is

6
In reality, it cannot be known what the value is later, as we will see, it is not initialized with any value. But for this
for example we can assume it is initialized to 0.
Introduction 35

increment ()
{
static int n;

n++;
printf ("n=%d", n);
}

is visualized, successively, n=1, n=2, ...

When the static class is applied to a global variable, it only becomes global from
file in which it is declared. Thus, in the example on the previous page, if in PROG1.C instead of the
we declare in the form

static int x;

there would be a linking error, even if it is declared as extern in PROG2.C.


Register class

The record class is identical to the auto class, therefore it can only be applied to local variables.
They only differ in the place where they are stored.

Any variable is stored, by default, in memory. If they are declared as class register,
Turbo C will try to keep them in a CPU register, in which case the processes will speed up in the
that intervene. Since the number of CPU registers is limited, Turbo C will keep the
variables in a record, if possible. Otherwise, it will convert it automatically.

A record class variable must be of the types char or int, and they are ideal for counters.
loops.

These variables cannot be applied the & (address of) operator.

Variable initialization

When declaring a variable, an initial value can be assigned to it, regardless of whether it
whether to maintain it throughout the entire program or not. Thus, statements such as are valid:

unsigned int x = 40000;


char letter = 'F';
register int b = 35;
Good morning

Global or static variables are initialized to 0 if no value is specified. Both


must be initialized with constant expressions.

Static variables are initialized by the compiler only once, at the beginning of the
program.

Automatic and registered variables have unknown values until one is assigned.
If they have initial values, they are assigned every time the block where they are defined is executed.
36 Introduction to the C Language

Exercises

1. Indicate the most appropriate data type to declare variables that store the values whose
The ranges are shown below:

a) Integers from 0 to 70,000


b) Integers from 1 to 100
c) Real numbers from 1 to 100
d) Integers from -100 to +100
e) Real numbers from -100 to +100
f) Integers from 0 to 10,000
g) Any uppercase letter
h) Integer numbers from 0 to 5,000,000,000
Numbers from -10.5 to 90.125

2. What does the following program do?

Error! Marker not defined.

void main ()
{
unsigned char character;

scanf("%c",&character);
character> 127 ? character++ : character--;
printf("%c", character);
}

3. Indica el tipo de variable (local/global), ámbito y tiempo de vida de las variablesa,b,cydde un


program that has the structure shown below:

int a;

void main ()
{
int b;
...
}

MyFunction()
{
int c;
static int d;
...
}
1. Introduction 37

Error! Marker not


defined.
Basic I/O

Types of I/O

It was already stated in Chapter 1 that C does not have specific reserved words that
handle the I/O. These operations are performed using library functions. These functions
They perform I/O operations that are classified as follows:

High-level I/O, defined by the ANSI standard. It is also referred to as a file system.
withbuffer.
Low-level I/O, or UNIX-type I/O.
I/Othroughconsole.

The two ANSI and UNIX standards are redundant. Turbo C supports both, but they should not
to use functions from both within the same program.

In this chapter, basic I/O operations via the console will be studied, meaning
Hello, the operations performed on the system's standard I/O, by default keyboard and screen.
We will also see that both input and output can be redirected to other devices, and how
do it, and also how to perform print output operations. Finally, we will study how
perform certain control over the screen in text mode (color, positioning, etc.). The operations of
I/O files will be studied in Chapters 10 and 11.

Character I/O

Functions getche() and getch()


They are the two basic functions that capture simple characters from the keyboard. The programs that
They must include the header file conio.h using a statement #include.
Both functions return the character read from the keyboard (without waiting for the key to be pressed. ). The function
getche() displays the typed character on screen. This is not the case with the getch() function. The correct usage of these
functions are through statements of the type

char a; It can also be declared as int.


...
38 Introduction to the C Language

...
a = getche (); /* or a = getch (); */

These functions do not have arguments. It is not mandatory to capture the character in a variable.
read. Thus, it is correct to write:

Press any key to continue ...


getch();

which halts the program until a character is available on the keyboard.

Error! Undefined marker. //Example: Displays theASCII code of a typed character

#include <stdio.h>
#include <conio.h>

void main ()
{
unsigned int character;

Press a key:
character= getche ();
YourASCII code is %u
}

This program produces an almost identical result using the getch() function. The only
the difference is the non-visualization of the character being typed. The format code %use is used in
printf() to display declared unsigned numbers.

putchar() function
For screen character presentation, in addition to printf() with the code of
format%c, the putchar() function. Programs that use this function must include the file
cabecerastdio.h. The correct use of putchar() is

char a; It can also be declared as int


...
...
putchar (a);

If the variable is of type int, it displays on the screen the character stored in the least byte.
significant. The sentences

char letter;
...
...
letra = 65;
putchar (letter);

They cause the display on the screen of the characterA, whoseASCII code is 65. It is equivalent to

putchar ('A');
1. Introduction 39

Sentences like this are also possible.

putchar (getch ());

whoseeffectisidenticaltothatproducedbythefunctiongetche().

Input/Output of character strings

In C, there is no specific data type for declaring character strings. As it has already been established
A string is defined as a vector of characters terminated with the null character.
'\0'. Thus, to declare a string of up to 30 characters, one must write

char string[31];

Although the study of character strings will be explored in depth in Chapter 7, it is necessary
to advance that C does not perform any boundary controls on arrays. That task is left in the hands of
programmer.

Function gets()
The basic function for inputting character strings from the keyboard is gets(). This function reads
keyboard characters until pressing the key , storing them in the specified string in the argument and
adding the null character at the end.

char phrase[31];
...
...
gets (phrase);

The function gets() does not check the limit. In the previous sequence, nothing will prevent the user
type more than 30 characters. The consequence of this is unpredictable, although surely the
the program will not function correctly.

It is important to note that the assignment of strings is not allowed.


through the operator=. These types of operations are performed using functions from the library
standard. Some of them will be studied in Chapter 6.

phrase = gets();

puts() function
The basic function for outputting character strings is puts(). This function writes to the screen.
the specified string in the argument also causes a newline. It is more
fast that printf() but does not allow formatting the output.

Tantogets() computes require the inclusion of the stdio.h file.


40 Introduction to the C Language

Error! Undefined marker. //Example with gets() and puts()

#include <stdio.h>

void main ()
{
charphrase[31];

Type a phrase:
gets (phrase);
You have typed: %s
}

In the previous example, the format code %s refers to strings. An effect


similar to the previous program, it is produced by the statement

puts (gets (phrase));

Formatted E/S
Input/Output with format is done through the functions scanf() and printf() that we already know.
We will study them now in more detail.

printf() function
As we have already seen, this function requires the inclusion of the header file stdio.h.
the general format is:

printf(control string, list of arguments);

The control chain determines how the rest of the arguments will be presented through the
format characters. For each format character in the control string there must be an argument
in the list. Otherwise, the result will not be correct. The valid format characters come
specified in the following table.

TYPE OF CHARACTER FORMATOF


FORMAT ARGUMENT EXIT
Numeric %d signeddecimalint
%i signeddecimalint
%o unsignedoctalint
%u unsigned decimal int
%x unsigned hexadecimal int (with a, ..., f)
%X unsigned hexadecimal int (withA, ..., F)
%f [-]dddd.dddd
%e [-]d.dddd or e[+/-]ddd
%g the shortest of %e and %f
%E [-]d.dddd or E[+/-]ddd
% the shortest of %E and %f
Character %c simplecharacter
1. Introduction 41

%s stringofcharacters
%% thecharacter%
Pointers %n theyrefertopointersandthemselves
%p theywillstudyinChapter7

Through formatting characters, certain aspects of presentation can be controlled.


data, such as length, the number of decimals, and left or right justification.

To indicate the length of a field, simply include an integer between the sign % and the
format character. Thus, %5d indicates that an integer will be presented in a field of 5
positions, justified to the right (unless otherwise indicated, the justification is always to the
right). Thus,

[ 47] visualize [ 47
[ 47] visualize [ 47
[ 47] visualize [ 47

where the symbol the rest of the chapter will represent a blank space. The brackets are only placed
to see the effect of formatting characters.

If left justification is desired, it is indicated with a negative sign.

[47 ] visualize [47 ]


[47 ] visualize [47 ]
[47 ] visualize [47 ]

When a numeric value is presented justified to the right, the field can be made to
fill with zeros instead of blank spaces, putting a 0 before the size indicator. Thus, the
sentence

[00047] visualize [00047]

This effect does not occur if left justification is requested.

[47 ] visualize [47 ]

When the data exceeds the field size, it is printed in full.

[1234] visualize[1234]

If the above applies to character strings, the result is as indicated.


continuation:

[%5s] : [ ABC ] visualize [ ABC


[000ABC] visualize [ ABC
[ABC ] visualize [ABC ]
[ABC ] visualize [ABC ]
[ ABCDE ] visualize [ABCDEF]

Applied to simple characters

[%3c] visualize [ A]
[%-3c] visualize [A ]

If you want to format a number with a decimal part, the format code is used.
42 Introduction to the C Language

%m.nf

the total length of the field (including the decimal point) and the number of decimals. Thus, the
format specifier %7.2f defines a field of 7 positions as follows: 4 for the part
whole number, 1 for the point and 2 for the decimals.

[ 12.30] visualize [ 12:30


[00012.30] visualize[0012.30]
[ 12.30] visualize 12.30 ]

When the number of decimals is greater than n, the last digit is rounded.

[ 12.35] visualize [ 12.35


[ 12.34] visualize [ 12.34

If this format applies to strings or integers, specify the size.


maximum of the field. Thus, %3.5s defines a presentation field for a string of at least 3
characters and no more than 5. If the string exceeds the maximum size, it is truncated.

[ABC] visualize ABC


[ABC] visualize [ABC]
[ABC] visualize [ABCDE]
[AB ] visualize [ AB
[ ABC ] visualize [ ABC

Format modifiers can be used to visualize integers short and long, by putting,
respectively, hylants ded, u, o, x, X.

%hd to visualize variables short int


%ld to visualize long int variables
%hu to visualize variables unsigned short int
%lu to visualize unsigned long int variables

The modifier can also be applied to a, e, f, g, E, G.

%lf to visualize long double variables

Function scanf()

It is the general-purpose formatted data input function that we have seen in the
Chapter 1. The syntax is similar to that of printf():

scanf (control string, list of arguments);

although here the control string should not be interpreted the same way as in printf().

We will classify the characters that can appear in the control string into 6 categories:

Format specifiers
Whitespace characters
Non-white characters
Character *
Length modifiers
Inspectiongame
1. Introduction 43

Format specifiers: They are the same as in printf() except for %gy%uy adding
%h. Thus, the sentence

char a; /* It can also be declared as int */


...
...
scanf("%c", &a);

captures a character and stores it in the variable a. The & operator is necessary in scanf() to simulate
calls by reference7and makes the function work internally with the address of the variable.
It is not necessary when the data to be captured is a string of characters.

char string[80];
...
...
scanf("%s", string);

although the ruling would have the same effect

scanf("%s", &string);

The reason why the operator is not necessary when it comes to strings is that the name of a
Achain (in general, from a matrix) without indices identifies the direction of the first element.

Whitespace characters: They are separators of input data. It is understood as a whitespace character.
any of the following:

Blank space(s)
Tabulator(s)
Return, Intro or line break )

When a whitespace character is specified in the control string, scanf() reads but does not store.
any number of whitespace characters until it finds the first one that is not.

scanf ("%c %d %s", &a, &b, &c);

stores in, byc, respectively, data entered in any of the following ways:

Y Y19 And 19 Hello 


19 Hello
Hello

and any similar combination.

One must be cautious with the use of blank spaces.Astatement like

scanf("%s ", string);

it will not return until a non-whitespace character is typed, since the space that is after %s
it makes spaces, tabs, and line breaks read and discarded.

Non-white characters: They are taken as separators of the input data. For example, in the
sentence

7
In call by reference to functions, any changes made to the parameters within the function take effect.
about the variables used in the call. This is not the case in call by value where changes to the parameters inside
the function does not reflect in the parameters of the call. We will study this in detail in Chapter 6, dedicated to Functions.
44 Introduction to the C Language

scanf ("%dHOLA%c", &num, &car);

an integer is read and stored in num, the characters HELLO are discarded (it is necessary to type them), and
any character and is stored in encar. Therefore, special care must be taken not to use the
control string descanf() as in printf(), and DO NOTWRITE statements like:

Enter a number: %d

Character *: When an * is placed between the % symbol and the format character, the type is read.
specified data but not assigned to any variable. The statement

scanf ("%d %*c %d", &num1, &num2);

read an integer and store it in num1, read a character and discard it (not assigned to any variable, and
read another integer and store it in num2. Thus, if a statement like the previous one is answered
typing something like

10-20

the value10ennum1 and the value20ennum2 would be stored.

Length modifiers: It is possible to limit the number of characters that are allowed in a
field writing a number after the symbol % of the format character. Thus, the statement

scanf ("%5s", sentence);

capture any typed string, but only store the first 5.


the rest of the characters are not discarded, but remain in the keyboard buffer available for
to be read by another scanf() statement. The following program illustrates the use of scanf() with modifiers.
of length.

Error! Undefined marker. // Example of scanf() with length modifier


#include <stdio.h>

void main ()
{
long int n1, n2;

Enter 2 integers:
scanf ("%5ld %5ld", &n1, &n2);
The entered numbers are %ld and %ld
}
If in this program the scanf() statement is answered with

123456

is displayed on the screen

The entered numbers are 12345 and 6

Inspection game: It is used only with %s and allows specifying which characters will be accepted.
They are indicated in square brackets. For example

char phrase[30];
1. Introduction 45

...
...
scanf("%[abc]s", phrase);

it only accepts the characters a, b, c. When a character that is not in the inspection set is typed
finalizes the entry for that variable. However, the statement will continue to accept characters until
that is typed leaving the uncaptured characters in the keyboard buffer, available for another
scanf() statements afterwards. Therefore, if there are two statements like

scan "%[abc]s", phrase;


scanf("%s", string);

anditistyped,forexample

abcbbapabcfgts

enfrasese will store the string abcbba, while encadenase will store abcfgts. The character
p, first different from [abc], acts as a terminator for the input to the variable phrase.

Ranges can be specified. For example

scanf("%[a-z]s", phrase);

it admits any character between laay laz. Also, the sentence

scanf("%[0-9][p-t]s", phrase);

it accepts any numeric digit and the characters pqrst.

It is possible to define reverse inspection games using the character ^. This indicates ascanf()
that must accept any character that is not in the inspection set. Therefore, the statement

scanf ("%[^0-9]s", phrase);

finish the entry by typing a numeric digit.


The fprintf() function
This function is practically identical to printf(). However, fprintf() allows you to associate the output with
different devices (screen, printer, text file, or other). The correct syntax for this
function is

fprintf (device, control string, argument list);

that is, it includes a first argument that relates the output to a device. In reality, that
the first argument must be a pointer to a predefined structure in C called FILE, from which
we will talk in Chapter 10. Anyway, for our current purposes, it is enough for us to
identify it in some way with a device.

As we will see in due time, C associates the devices with certain areas or memory buffers.
called channels. When a program starts executing, 5 channels are automatically opened,
among them the one associated with the printer. This device is referenced by the word stdprn.

Therefore, fprintf() directs its output to the printer when it is written in the form

fprintf (stdprn, control string, list of arguments);


46 Introduction to the C Language

All other features of defprintf() are identical to those of printf().

Text screen control

The screen control can be established in two ways. Firstly, Turbo C provides
a large number of functions to control the screen in both text mode and graphic mode.
In this section, we will study some basic control functions in text mode. All of them
they need to include the header file cabeceraconio.h. Another way to control the screen is by
throughANSI escape sequences.

Library functions

Function clrscr(): Clears the screen and places the cursor in the top left corner.
does not require arguments nor returns any value.

Function clreol(): Clears a line from the screen from the cursor position to the end of
that line. It also does not need arguments nor returns any value.
Functions insline() and delline(): The function insline() inserts a blank line below the
with the cursor, shifting the rest down one line. Similarly, the function delline() deletes the
line where the cursor is, moving the ones below upwards.

Functions gotoxy(), wherex() and wherey(): The function gotoxy() is responsible for positioning.
fromthecursor.Itiswritten

int row, column;


...
...
gotoxy(column, row);

The functions where x() and where y() return the coordinates of the current cursor position:

int row, column;


...
...
column = wherex ();
row = wherey();

In these 3 functions, the variables row and column must be declared as of type int.

Function movetext(): Copies text from one area of the screen to another. The syntax of this function
is

int x1, y1, x2, y2, x3, y3;


...
...
movetext (y1, x1, y2, x2, y3, x3);

being:

x1, y1: column, row of the upper left corner of the area of the screen to scroll.
1. Introduction 47

x2, y2: same as the bottom right corner.


x3, y3: column, row of the upper left corner of the screen where it moves to
text.

The function does not delete the text from the original position. It returns 0 if any coordinate is out of range.
of range, and 1 otherwise.

Functions highvideo(), lowvideo() and normvideo(): The first two set, respectively,
the screen text at high and low intensity. The function normvideo() restores the intensity of the
screen to the state it was in when the program started.

textcolor(), textbackground() and textattr() functions: The textcolor() function sets the color
from the text presented from the moment the function is executed.

textcolor (character_color);

The parameter character_color is a number between 0 and 15. Each of these numbers
it is associated with a color.Additionally, in the archivoconio.hse file, a macro is defined for each color. This remains
reflected in the following table:

VALUE COLOR MACRO

0 Black BLACK
1 Blue BLUE
2 Green GREEN
3 Turquoise CYAN
4 Red RED
5 Purple MAGENTA
6 Brown BROWN
7 White LIGHTGRAY
8 Gray DARKGRAY
9 Intense blue LIGHTBLUE
10 Intense green LIGHTGREEN
11 Intense turquoise LIGHTCYAN
12 Intense red LIGHTRED
13 Intense purple LIGHTMAGENTA
14 Yellow YELLOW
15 Intense white WHITE
128 Blinking BLINK

Taking this into account, to get a text to be presented, for example, in green color,
prior to writing it must be done

textcolor (2);

orwell

textcolor (GREEN);

However, this has no effect if the functions printf(), puts(), gets(), and putchar() are used.
Instead, the functions cprintf(), cputs(), cgets(), and putch() should be used, respectively.
the function getche() is valid.

To achieve the character's blinking, an OR operation must be performed between the color and the value.
128 (BLINK). Therefore, if we want to present a text in blinking yellow, we must write
48 Introduction to the C Language

textcolor (YELLOW | BLINK);

The function textbackground() sets the background color for all text that is written in
screen below.

background (background_color);

being_background_color a value between 0 and 7, corresponding to the previous table.

The function textattr() sets the complete attribute byte (character color, background color,
blinking yes/no and high/low intensity). It is written

textattr (attribute);

where attribute is a byte whose meaning is shown below

7 6 5 4 3 2 1 0
P F F F I C C C

where CCC are the bits that encode the character color, I is the intensity bit, FFF indicates color
in the background, and P is the blinking bit. The most convenient way to use this function is as follows: it
multiply the background color number of the table by 16 and perform an OR operation with the color of
character. If you also want the text to blink, you must perform an OR operation with the value 128
(BLINK). Thus, to obtain a blinking text in yellow on a blue background, it must be done:

textattr (YELLOW | BLINK | BLUE * 16);

Function textmode(): Assigns a specific video mode to the text screen:

text mode (video_mode);

The allowed values for video_mode and the associated macros are shown in the table.
next.

MODE OF description MACRO


VIDEO
0 Black and white, 40 columns BW40
1 Color, 40 columns CO40
2 Black and white, 80 columns BW80
3 Color, 80 columns CO80
7 Monochrome MONO
-1 Previous mode LASTMODE

When assigning a video mode, the screen is initialized.

ANSI escape sequences

The ANSI.SYS file is a screen and keyboard driver that allows you to change the
presentation of texts and graphics on screen, control the cursor and change the assignments of the
1. Introduction 49

keys. Each of these functions is defined by an ANSI escape sequence, which is a


string of characters that begins with the characters ESC [, being ESC the ESCAPE character,
ASCII code 27 (033 octal). These escape sequences are described below.

OPERATION SEQUENCE description


OF ESCAPE
Displacements ESC[#;#H Place the cursor at the position on the screen
by the cursor marked with #;# (the first number indicates the
row and the second the column
Move the cursor # lines up
ESC[#B Move the cursor # lines down
ESC[#C Move the cursor # columns to the right
ESC[#D Move the cursor # columns to the left
ESC[s Save the current cursor position
ESC[u Restore the previous cursor position
saved with the previous sequence
Deleted Clear the screen and place the cursor in the
upper left corner of the screen
ESC[K Delete all characters from the position
actual of the cursor to the end of the line
Set ESC[#;...;#m Calls the specified graphic functions
of graphs through the digits #. These functions
remain active until the next one
appearance of this escape sequence. The
Allowed values for # are shown in the
table on the next page
Establish mode ESC[=#h Change the width or type of screen. The
of video allowed values for # are shown in the
table of the next page
ESC[=#l Reset the mode using the same ones
values that the previous sequence uses, except
the mode 7 that disables automatic adjustment
line. The last character of the sequence is
the lowercase l
Reassignment of ESC[#;cad;#p Allows changing the definition of the keys to
chains for the a specific string. The symbol #
keyboard represents the code or codes generated by
the key to be reassigned. provides the ASCII code
corresponding to a single character or to a
string in quotes.

Example 1:
convert A into B.

Example 2:
Assign to the F1 key
(that generates the codes 0 and 59) the CLS chain
together with (code 13).
Allowed values ATTRIBUTES 0 Deactivate all attributes
for # in the OF TEXT 1 High intensity activated
escape sequence 4 Underscore (monochrome monitor)
5 Blink activated
7 Reverse video activated
8 Hidden activated
COLOR OF 30 Black
CHARACTER 31 Red
50 Introduction to the C Language

32 Green
33 Yellow
34 Blue
35 Magenta
36 Violet
37 White
COLOR OF 40 Black
FUND 41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Violet
47 White
Allowed values 0 40x25 monochrome (text)
for # in the 1 40x25 color (text)
escape sequence 2 80x25 monochrome (text)
ESC[=#h 3 80x25 color (text)
4 320x200 color (graphics)
5 320x200 monochrome (graphics)
6 640x200 monochrome (graphics)
7 Activate automatic line adjustment
13 320x200 color (graphics)
14 640x200 color (16 color graphics)
15 640x350 mono (2 color graphics)
16 640x350 color (16 color graphics)
17 640x480 mono (2 color graphics)
18 640x480 color (16 color graphics)
19 320x200 color (256 color graphics)

An ANSI escape sequence is sent, for example, through the printf() function. With
Hello, the characters of the escape sequence are not displayed, but the effect is achieved.
described for each of them. But for these sequences to have the expected effect, it is
It is necessary to install the ANSI.SYS driver in the CONFIG.SYS file using a statement.
DEVICE or DEVICEHIGH. The syntax for installing this driver is:

DEVICE =[unit:] [path]ANSI.SYS

so that if the file ANSI.SYS is in the \\DOS directory of drive C:, in the file
CONFIG.SYS must have a line

device = c:\dos\ansi.sys

or, if you wish to install in upper memory


c:\dos\ansi.sys

Let's look at some examples that illustrate the use of these escape sequences.

Cursor positioning: The escape sequence for positioning the cursor is

ESC [f;cH (f = row, c = column)

To position the cursor at row 5, column 20, do the following

printf ("\033[5;20H");
1. Introduction 51

and produce exactly the same effect as

gotoxy (20, 5);

However, for this type of operations, it is more convenient to define a function that
receive the coordinates in the parameters:

set_cursor (int row, int column)


{
printf ("\033[%d;%dH", row, column);
}

In a program, this function would be called, for example, through

move_cursor (5, 20);

Screen clearing: The ANSI sequence that clears the screen is

ESC [2J

Therefore, the sentence

printf ("\033[2J");

produce the same effect as the library function clrscr(). It can be abbreviated in writing
this sequence using a macro like

#define CLS printf (" [2J")

and use statements in the program

CLS;

Redefinition of keys: We will show the use of this sequence through an example that
Assign the F1 key (which, when pressed, generates the codes 0 and 59) the character string DIR
C:/P This is achieved with the sequence

DIR C:/P

This is written with a printf() function

printf ("\033[0;59;\"DIR C:/P\";13p");

or also

printf ("\033[0;59;%c%s%c;13p", 34, "DIR C:/P", 34);

where it should be taken into account that the ASCII code of the double quote (" ) is 34.

Input/Output Redirection

The I/O operations performed by functions related to the console (printf(), scanf(),
) can be redirected to other devices through the operators
52 Introduction to the C Language

output redirection
input redirection

Output redirection
Be the program on page 2, compiled and linked as DOCENA.EXE. If from the
indicator of the DOS we write:

C:\> dozen >prn

The phrase "A dozen is 12 units" is not displayed on the screen, but is directed to the device.
prn(printer). You can also redirect the phrase to a text file called,
example, SENTENCE.TXT, by means of

C:\> age >phrase.txt

This command creates a text file called FRASE.TXT in the root directory that stores the
A dozen is 12 units. If the file already exists, its previous content is lost.

Every time the output is redirected to a file, it is created anew. Thus, the sequence

C: prog1 >fich.txt
C:\> prog2 >fich.txt

create a file FICH.TXT that stores the output only from PROG2. If you want to add the
Output of a program to an existing file without destroying its content is done using the operator >>.
The sequence

C:\> prog1 >file.txt


C:\> prog2 >>file.txt

store in FICH.TXT the output of both programs PROG1 and PROG2.

Input redirection
Now the program PIES.C on page 5 compiled and linked as PIES.EXE.
Let's create a text file called DATO.DAT that stores the number 3. This is achieved
from the DOS indicator through the sequence

C:\> copy con data.dat


3

C:\>

If we write

C:\> pies <data.dat

the scanf() statement of the program no longer reads the data from the keyboard. With the input redirected,
it takes from the file DATO.DAT. We would then see on screen the messages generated by
printf(). Something like

Feet?:
3 feet = 0.925200 meters
1. Introduction 53

Redirection of input and output


You can redirect both input and output at the same time. If we write

C:\> pies <data.dat >messages.txt

we will not see anything on screen, and a text file is created in the root directory called
MESSAGES.TXT that stores the messages generated by the two printf() statements.
54 Introduction to the C Language

Exercises 8

1. Write a program that reads an ASCII code (an integer between 0 and
255) and display the corresponding character on screen.

2. Write a program that reads any character from the keyboard and displays it on the screen.
ASCII code in decimal, octal and hexadecimal.

3. Write a program that reads two floating-point numbers from the keyboard, whose integer part...
assume that it does not exceed 3 digits, and display its sum adjusted to the right on the screen. For
for example, if the numbers are 23.6 and 187.54 the program should display:

23.60
187.54
----------
211.14

4. Write a program that reads 2 three-digit integers and prints their product. For
example, if the numbers are 325 and 426 it will be presented in the format

325
x 426
------------
1950
650
1300
------------
138450

The date of Easter corresponds to the first Sunday after the first full moon that
it follows the Spring equinox, and it is calculated with the following expressions:

A = remainder of (year / 19)


B = remainder of (year / 4)
C = remainder of (year / 7)
D = remainder of (19 * A + 24) / 30
E = remainder of (2 * B + 4 * C + 6 * D + 5) / 7
N = 22 + D + E

in which N indicates the day of the month of March (April if N > 31, in which case the
day is N - 31) corresponding to Easter Sunday. Write a program that accepts a
Enter the year via keyboard and display on screen the date of the first Easter Sunday with the
dd/mm/yyyy format.

8
Use text screen control functions or ANSI escape sequences (clearing) in all screen outputs.
screen, cursor positioning, colors, etc.
1. Introduction 55

6. Write a program that reads the following data from the keyboard for 2 people: name, age,
height and weight. The program will send a list to the printer with the format:

NAME AGE HEIGHT WEIGHT


xxxxxxxxxxxxxxxxxxxxxx xx xx,x xxx,xx
xxxxxxxxxxxxxxxxxxxxxx xx xx,x xxx,xx

Media: xx,xx xx,xx xxx,xx

5! Error! Marker not


defined.
Control statements

The if structure

The structure takes one of the following two forms:

if (expression) statement;

orwell

if (expression) statement;
the sentence;

where expressions evaluate a statement that is true (returns a non-null value) or false
(returns zero). The word sentence can be a simple statement ended with a semicolon, or
a group of statements enclosed in curly braces {}. Some valid examples of statements are:

if (x > 0) puts ("POSITIVE");


if (x) puts("True");
else puts ("False");
if (c >= 'a' && c <= 'z') {
The variable c stores an alphabetical character
The character is a lowercase letter
}
if (num <= 40000) {
Octal: %o
printf ("\nHexadecimal: %X", num); }
else {
The number is greater than 40000
printf("Your value is %u", num);
}
56 Introduction to the C Language

If structures can be nested simply by taking a minimum of precautions. In the


sentences

if (x)
if (y) puts ("1");
else puts ("2");

else is associated with if (y). C always associates the closest else to an if that does not already have an else.
In the previous sentence, the selection associates to if (x), it is necessary to place the brackets {} properly.

if (x) {
if (y) puts ("1"); }
else puts ("2");

In C, the structure is also available

if (condition1) statement1;
else if (condition2) statement2;
else if (condition3) statement3;
...
the sentence N;

which evaluates, successively, condition1, condition2, ... When it finds a certain one, it executes the
corresponding statement and elif is finished. If none is true, the statement that accompanies it is executed.
else (which is not mandatory). As always, statement1, statement2, ..., can be a single statement
or a group of them, in which case they are enclosed in braces {}.

The following program uses this structure to determine if a number is positive, negative, or
zero.

Error! Undefined marker. #include <stdio.h>


#include <conio.h>

void main ()
{
int n;

clearscreen();
Enter an integer number:
scanf "%d", &n;

if (n > 0) puts("Positive");
else if (n < 0) puts("Negative");
else puts ("Zero");
}

The switch structure


1. Introduction 57

The switch structure inspects a variable and compares it with a list of


constants. When a match is found, the associated statement or group of statements is executed.
The way switches
switch (variable) {
casecte1: sentence;
break;
casecte2 sentence;
break;
...
...
default sentence;
}

wherevariable is a variable or any expression that returns a value. The switch statement
compare the variable cte1, cte2, ..., and if it finds a match, execute the statement
corresponding. By sentencing we must understand both a simple sentence and a group of
sentences (which, in this case, are not enclosed in braces). If no match is found, then
executethedefaultsection(whichisnotmandatory).

The following program segment shows how to use the switch statement.

charc;
...
...
c = getche();
switch (c) {
case 'a': function_a();
break;
case 'b': function_b();
break;
default: puts("Neither a nor b has been pressed");
}

Let us note that the switch statement looks for exact matches, so it is not an alternative.
programs like the one on the previous page, as it is NOT ALLOWED to impose conditions of
inequality. It is not correct, therefore

int n;
...
...
switch (n) {
case > 0: puts("Positive");
break;
case < 0: puts("Negative");
break;
default: puts ("Zero");
}

The break statement is optional. When encountered, it causes the exit from switch. In case
Continue with the following sequence case default even if the condition is not met. To clarify.
this, let's take the following example:

int c;
...
...
scanf ("%d", &c);
58 Introduction to the C Language

switch (c) {
case 1:
case 2: Function2 ();
case 3: Function3 ();
break;
case 4: Function4_1();
Function4_2 ();
break;
case 5: Function_5 ();
default: FunctionX ();
}

The following table indicates which function is executed depending on the value of dec.

Error! Marker not It is executed


defined. If pressed

1 Function2() and Function3()

2 Function2() and Function3()

3 Function3()
4 Function4_1() and Function4_2()

5 Function5() and FunctionX()

any other thing FunctionX()

The default sentence is optional. When it is not present, no action is taken when all fail.
Matches. Simply abandon the switch without doing anything. If there is a default statement, the block
The associated statements are executed when all comparisons fail or there is no previous break.
it prevents it. Switch statements can be nested, allowing for structures of the type:

switch (m) {
case 1: Function1 ();
break;

case 2: switch (n) {


case 21: Function21();
break;

default: switch (p) {


case 31: Function31 ();
break;
case 31: Function32();
}
}
break;
default: FunctionX();
}
Loops
There are three types of loops in C: for, while, and do/while.
1. Introduction 59

For loops

The loop is very powerful and flexible. In addition to allowing the same operations as
Any language, like others, has characteristics that clearly differentiate it from them. In its
traditional format this loop has the form

for (initialization; condition; increment) body_of_the_loop;

We see that it has three sections: initialization, where an initial value is given to a variable.
control of the loop; condition, which is an expression that returns a true or false value, and does
that the loop repeats while it is true; increment, where the amount is determined
increment or decrement of the control variable. The three sections are separated by a semicolon.
The body of the loop can be made up of one or several statements. In this last case, they must
enclose within braces {}. The flow of statements in this loop is as follows:

initialization

FALSE
condition

TRUE

loop_body

increase

Let's note that the loop continues to execute WHILE the condition is true.

Let's look at a couple of examples. In the following sequence, the numbers are displayed on the screen.
1 al 10 y sus cuadrados.

register int i;
...
...
for (i = 1; i <= 10; i++) {
Value of i: %d
Value of i2: %d", i * i);
}

In this, the uppercase letters from A to Z are displayed on the screen.


60 Introduction to the C Language

char letter;
...
...
for (letter = 'A'; letter <= 'Z'; letter++) printf("\n%c", letter);

You can set an increment/decrement different from 1. The following example shows in
display the even numbers between 1 and 100, in descending order:

register int i;
...
...
for (i = 100; i >= 1; i = i - 2) printf("\n%d", i);

We will now study some forms of deformation that depart from traditional use.

It is possible to have more than one control variable in the loop: In the for loop the sections of
initialization and increment can, in turn, have subsections, in which case they are separated by the
sequential operator (,).An example is

register int i, j;
...
...
for (i = 0, j = 1; i + j < N; i++, j++) printf(" %d", i + j);

which visualizes the first N odd numbers. This statement should not be confused with nesting
of for loops. A nesting looks like this:

register int i, j;
...
...
for (i = 0; i <= 100; i++) {
...
for (j = 0; j <= 100; j++) {
loop_body;
}
...
}

The loop exit condition does not have to refer to the control variable: This
is illustrated in the following example:

char a;
register int i;
...
...
for (i = 1; a != 's'; i++) {
%d
a = getch();
}

In this example, the numbers 1, 2, ... are displayed on the screen until the character is typed.

The for loop may have no body: This feature allows creating delays in a program.
The loop

register int i;
...
...
1. Introduction 61

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

causes a delay of 100 cycles.

The for loop can have any section empty: In a for loop, one, two, or all sections can be missing.
three sections. For example, it is correct to write

register int i;
...
...
for (i = 0; i != 10; ) { /* Missing the 3rd section (increase) */
scanf ("%d", &i);
%d
}

that shows on screen the values that are typed, ending when the number 10 is typed (which
it is also visible.

Itisalsocorrecttohavealooplike

for ( ; ; ) {
loop_body;
}

what is an infinite loop. We will study later, in this same chapter, how to exit a loop
infinite.

Any valid expression in C can be in any section of a for loop: The form
The loop structure must necessarily conform to the one shown on page 67. In reality, the form
thecorrectoneis:

for (expression1; expression2; expression3) loop body;


beingexpressionNany valid expression C. We can say that, in general, the flow of statements
of a feedback loop:

expression1

FALSE
expression2

TRUE

loop_body

expression3
62 Introduction to the C Language

We will clarify this with the following program:

Error! Marker not defined.


void main ()
{
int t;
for (message (); t = read_number (); square (t));
}
message
{
Type a number (0 ends):
}
read_number()
{
int n;
scanf("%d", &n);
return n;
}
square (int x)
{
The square is %d
}
Let's take a look at the for loop of the main() function and explain it using a flowchart.
from the previous page.

The function mensaje() is executed which displays the string 'Type a number (0 ends): '.
(IMPORTANT:This function only runs this time).
2. The expression t = read_number() is evaluated, that is, read_number() captures an integer.
from the keyboard and returns it by storing it.
2.1 If the expression t = read_number() returns FALSE, that is, if 0 has been typed,
end the loop.
2.2 Otherwise, continue the loop.
3. The body of the loop is executed. In this case, since 'for' ends with a semicolon, there is no
body of the loop.
4. The function square(t) is executed, which displays the square of the entered number.
5. Go back to step 2.

The while loop

It has the shape

while (expression) loop_body;

any valid expression C. The body_of_the_loop can be made up of a


simple statement or by a block of statements, in which case they are enclosed in braces {}. The flow of
sentences is
1. Introduction 63

FALSE
expression

TRUE

body_of_the_loop

Therefore, in the while loop, the body of the loop repeats while the expression evaluates as
certain. Let's look at some examples.

char c;
...
...
while (c != 's' && c != 'n') c = getche ();

In this statement, a character from the keyboard is requested as long as the character is not entered.
characters. When one of these characters is typed, it is stored and the loop is abandoned.

The following example is a case of while loop without a body.

while (getch() != 13);

The program is paused at this statement until a key is pressed. (ASCII code 13).

The following program uses a while loop to ask the user to guess a number.

Error! Marker not defined.#include <stdio.h>


#include <stdlib.h>

void main ()
{
int num;
int n = 0;

randomize (); The functions randomize() and random() allow


num = random(20) + 1; //generate random numbers

while (n != num) {
Type a number between 1 and 20:
scanf("%d", &n);

if (n == num) puts ("YOU GOT IT");


else if (n < num) puts("YOUR NUMBER IS LOWER");
ELSE PUTS ("YOUR NUMBER IS GREATER");
}
}
64 Introduction to C Language

Regarding the while loop, it is important to keep the following in mind:

The body of the loop will NEVER execute if the condition is not met the first time.
The loop can be INFINITE if the variables are not properly modified.
condition within the loop.

The do/while loop

It has the shape

do
loop_body;
while (expression);

being a sentence a simple sentence or a group of statements enclosed in braces {}, and expression
any valid C expression. The flow of execution is as follows:

loop_body

TRUE
expression

FALSE

Therefore, in a do/while the body of the do is executed at least once, even


although the expression is evaluated as false, since the evaluation is done at the end, just the opposite of
while loop, where the expression evaluation is done at the beginning.

In the following example, a character is requested from the keyboard until any of the keys is pressed.
characters 'S' or 'N'.

#include <stdio.h>

void main()
{
char key;

do {
Pulse S or N:
key = getch();
} while (key != 'S' && key != 'N');
}
1. Introduction 65

Break statement

It is the same statement that we have seen to finalize the cases of the switch statement. But
it also allows forcing the immediate exit of a loop (for, while/odo/while) at any time,
ignoring the rest of the sentences. Let's see an example:

#include <stdio.h>

void main ()
{
int n;

for ( ; ; ) {
Type a number:
scanf("%d", &n);
if (!n) break;
The square is %d
}
}

In this example, the for loop would run indefinitely unless there is the statement

if (!n) break; //It is the same as if (n == 0) break;

Numbers are requested from the keyboard and their squares are displayed until a 0 is typed.
would evaluate as true), in which case the break statement is executed, which causes an immediate exit from the
loop without the printf statement being executed at the end.

Sentence continues

This statement is used in for, while, and do/while loops. When executed, it forces a new
loop cycle, skipping any subsequent statement. For example, the loop

int i, n;
...
...
for (i = 1; i <= 100; i++) {
n = i / 2;
if (i == 2 * n) continue;
%d
}

only display the odd numbers, since for the even numbers the expression
i == 2 * nse evaluates as true, executing the continue statement that immediately forces a new
loopcycle.

The following program shows how the continue statement acts in a do/while loop.
66 Introduction to the C Language

Error! Undefined marker.

void main ()
{
int n;
int positivos = 0;

clearscreen();
do {
Type a number (-99 ends):
scanf ("%d", &n);
if (n <= 0) continue;
positives++;
} while (n != -99);

You have entered %d positive numbers


}

The positive sentence only executes when there is a positive number. If it is negative or zero.
0, continue forces a new evaluation of the loop's exit condition.

Labels and goto statement

In C there is the unconditional jump statement goto that forces a jump in the program to a
line identified by a label. The label is defined with a valid identifier C, followed by two
points (:).

goto label;
...
...
label: sentence;
...
...

The label can be before or after the goal, but always in the same function.
Actually, in languages with sufficient control structures (like C), they usually do not occur.
situations that make the sentencing necessary. However, on some occasions it can be
convenient, well because the processing speed is important (a jump with a cot isn't faster than
another type of branching controls), or because their use clarifies the code. The most common case is the
output of various levels of nesting.

for (...) {
while (...) {
for (...) {
...
...
if (...) go to exit;
...
...
}
}
1. Introduction 67

}
go out: ...
...

In this example, the only alternative would be to carry out several checks on.
each loop that forced break statements, which would make the code more unreadable.

exit() function

This function allows the program to be terminated at any point in it. It returns the
control of the operating system or another parent process, by sending a return value. Inclusion is necessary
from the header file process.h, by means of a statement #include.

If in a program we write

if (condition) exit (0);

the program ends when certain conditions are met, in which case the value 0 is returned to the
parent process.

The program shown below (SINO.C) will be executed from a BAT file
(parent process). The SINO program will pass a return value to the parent process through the
exit function(). The parent process inspects this return value using ERRORLEVEL.

Error! Undefined marker. /* Program SINO.C: Accepts the character 's' or the
character 'n'. In the first case ('s') it returns a value of 1.
In the second case ('n') it returns a value of 0 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

void main ()
{
charletter;

do
letter = getch();
while (letter != 's' && letter != 'n');

if (letter == 's') exit (1);


exit (0);

End of the program This statement never executes


}

We compile and link this program as SINO.EXE and include it in a file by


lots like the following:
68 Introduction to the C Language

Error! Undefined marker.


ECHO PressYes orNo
SINO
IF ERRORLEVEL == 1 GOTO SI
GOTO NO
YES
ECHOYou pressedYES
GOTO FIN
NO
ECHOYou pressed NO
:FIN
@ECHO ON

This file displays the message "You clicked YES" when the character is typed in NO, and
Display the message 'You pressed NO' if 'YES' or 'NO' is typed in. In no case is it displayed
End of program
1. Introduction 69

Exercises

1. Write a program that assigns a literal grade to a student, based on the following
score table:

8.5 to 10 Outstanding
7 to 8.5 Notable
6 to 7 Good
5 to 6 Sufficient
3.5 to 5 Insufficient
0 to 3.5 Very poor

The program will capture a numeric value from the keyboard and display the grade.
corresponding. The fails will be displayed in yellow flashing on a red background, the
outstanding in yellow on a blue background, and the rest in black on a green background.

2. Write a program to determine if an athlete is selected to run a marathon. For


select a runner, they must have finished a previous marathon in a certain
qualification times are 150 minutes for men under 40 years old, 175
minutes for men over 40 years old, and 180 minutes for women. The data to be entered
son: sex (M/F), age and time taken in their previous marathon. The program will display the
Selected

3. The employees of a factory work in two shifts: daytime and nighttime. It is desired to calculate the
daily newspaper according to the following criteria:

a) Daytime hours are paid at 1000 pesetas.


b) Night hours are paid at 1600 pesetas.
c) In the case of being Sunday, the rate will increase by 400 pesetas for the daytime shift and in
600 the nocturne.

4. Write a program that calculates and prints the sum of the even and odd numbers included.
between two valuesAand B that are entered via keyboard (A< B).

5. Write a program that calculates xn, being integers that are introduced by
keyboard.

6. Write a program that calculates the factorial of a positive integer that is entered by the user.
keyboard.

7. Write a program that finds the first valueNfor which the sum

1 + 2 + 3 + ... + N

exceeds a value that is entered via keyboard.


70 Introduction to the C Language

8. Write a program that calculates the first element of the Fibonacci series that is greater than or
the same as a value entered by keyboard. The Fibonacci series is defined by:

a0= a11 an= an-1 + an-2

9. The value of it can be calculated using the series

= 4 * ( 1 - 1/3 + 1/5 - 1/7 + 1/9 ...)

Write a program that calculates the value of To choose the number of terms of the series
adopts the criterion that the absolute difference between the real value of (3.141592) and the value
calculated to be less than 10-3Create a function that returns the absolute value of a
expression.

Error! Marker not found.


defined.
Functions

Introduction
One of the most appropriate ways to solve a programming problem is
decompose it into subproblems. Each of them is associated with a function that solves it, in such a way
so that the solution to the problem is obtained through function calls. In turn, each
function can be decomposed into subfunctions that perform more basic tasks, trying
ensure that each function performs one and only one task.

In C language, a function is defined as follows:

typeFunctionName(formalparameters)
{
...
body of the function
...
}

The type of data that the function returns through the return statement whose study
it was brought forward on page 8. When a type is not specified, it is assumed that the returned type is int.
FunctionName is a valid identifier in C. It is the name by which it will be called.
function from tomorrow() or from other functions. The formal parameters are the local variables
through which the function receives data when invoked. They must be enclosed in parentheses.
Even if there are no formal parameters, parentheses must appear. The following function returns the
greater of two integers:
1. Introduction 71

int greater(int x, int y)


{
int max;

if (x > y) max = x;
else max = y;

return max;
}

When handling functions in C, we must keep in mind that a function can only be accessed
by means of a call. You can never jump from one function to another using a goto statement.
It is also not allowed to declare a function within another.

In C, unlike other languages such as Pascal, there is no distinction between functions and
procedures. Therefore, a function can or cannot be within an expression. If the function returns
a value, statements of the type are valid:

a = b * function(c, d);

But we can also find standalone functions in a line of code,

function (a, b, c);

even if the function returns a value. In that case, the function would perform the assigned task
and the returned value would be lost. This does not cause any error.

Finally, we must take into account that, although a function can be part of a
complex expression, it can never be assigned a value. Therefore, it is incorrect to write statements
how

function () = variable;

what would be as inappropriate as writing

5 = variable;

The only method for a function to receive values is through formal parameters.

Function arguments
The formal parameters are local variables that are created when the function begins and are
they destroy upon exiting her. When calling the function, the formal parameters must match in
type and in number with the variables used in the call, which we will refer to as arguments of
the function. If they do not match, the error may not be detected. This is avoided by using the so-called prototypes.
of functions that we will study later, in this chapter.

The arguments of a function can be:

values (called by value)


directions (called by reference)
72 Introduction to the C Language

Calls by value

In call by value, a copy of the argument's value is made in the formal parameter. The
function operates internally with these last ones. Like the local variables of a function (and the
formal parameters are created when entering the function and destroyed upon exiting it, any
Change made by the function in the formal parameters has no effect on the
arguments. Let's clarify this with an example.

Error! Marker not defined.#include <stdio.h>

void main ()
{
int a = 3, b = 4;

swap (a, b);


Value of a: %d - Value of b: %d
}

void swap(int x, int y)


{
int aux;

aux = x;
x=y;
y = aux;
}

The output of this program is:

Valorde a: 3 -Valorde b: 4

that is, it does NOT swap the values of the variables a and b. When the call is made

swap (a, b);

thevalueofdeaenxiscopied,andthedebeny.Thefunctionworkswithxey,whicharedestroyedattheend,without
that no reverse copying process takes place, that is, dexeyhaciaayb.

Calls by reference

In this type of calls, the arguments contain addresses of variables. Inside the
The function the address is used to access the real argument. In calls by reference, any
Change in the function affects the variable whose address was passed in the argument. This is so.
because it works with its own memory address, which is unique, and there is no process of
creation/destruction of that address.
Although in C all function calls are made by value, call by reference can be simulated.
reference using the operators &(address) and *(at the address). Through & we can pass
variable addresses instead of values, and work internally in the function with the contents,
through the operator *.

The following program demonstrates how content exchange can be achieved between two
variables, through a function.
1. Introduction 73

¡Error! Marker not defined.#include <stdio.h>

void main ()
{
int a = 3, b = 4;

swap (&a, &b);


Value of a: %d - Value of b: %d
}

void swap (int *x, int *y)


{
int aux;

aux = *x;
*x=*y;
*y = aux;
}

This program DOES exchange the values of a and b, and displays the message

Valorde a: 4 -Valorde b: 3

In addition, unlike the one on page 83, it works with addresses. As we will see in the next one.
chapter, in the statement

void intercambio(int *x, int *y);

The parameters x and y are special variables, called pointers, that store addresses.
from memory. In this case, they store addresses of integers.

Return values of a function

As we have already seen, there are two ways to exit a function: either because it ...
"find" the key that closes the function, either because a return statement is executed. In this last
the form of the sentence can be any of the following:

return constant;
returnvariable;
return expression;

where expression can, for clarity, go in parentheses. The value returned by return must be
compatible with the declared type for the function.

As we saw at the beginning of the chapter, if a function does not return any type it returns a
value of tipoint, so it must have a return statement that returns an integer. Without
embargo, the absence of this sentence only causes a warning during compilation. Of any
way, if a function does not return any value (there is no return statement) it is correct to declare it as
tipovoid.
74 Introduction to the C Language

It is not necessary to declare functions of type char either, as C performs a clean conversion between
thetypesarechareint.

Function prototypes

When a function returns a non-integer type, you need to "let it be known" before using it.
rest of the program using function prototypes. A function prototype is something that indicates to the
compiler that there is a function and what is the correct way to call it. It is a kind of 'template'
of the function, with two objectives:

identify the type returned by the function.


identify the type and number of arguments that the function uses.

The way to define a function prototype is:

type FunctionName (list of types);

The types of the arguments are placed in parentheses, separated by commas (not necessary
put the name) in the same order in which they should be in the call. Thus, a prototype like the
next

float Example (int, char);

indicates that the program is going to use a function called Example that returns, through a
return statement, a value of type float, and it receives two values as its arguments: the first is a value
integer and the second a character. It is also a valid prototype.

float Example (int x, char y);

In a program, the function prototypes are located before the main function.
The following shows a program that defines a function prototype.

#include <stdio.h>

float multiply (float, float); /* Prototype of the function multiplies() */

main ()
{
float a, b, total;

Type in the numbers:


scanf("%f%f",&a,&b);
multiply(a, b);
printf("\nThe product of both is %f", total);
}

float multiply(float m, float n)


{
return m * n;
}
1. Introduction 75

In this program, if instead of the line

total = multiply(a, b);

we would write

total = multiply(a);

the compiler, alerted by the prototype, would report the error.

Both in prototypes and in function declarations, references to strings of


characters are created using the expression char *. The meaning of this expression will be understood more
clearly in the next chapter. Thus, the prototype of a function that returns a string of
characters and has as its only argument a string of characters is

char *Function (char *);

When a function has a variable number of arguments, it is specified by means of 3


ellipsis. This is the case of the printf() function whose prototype is:

int printf (const char *, ...);

The reserved word here means that the referred string with char * can be either a
variable, as in

printf (string);
or a constant, as in

Constant string

To indicate that a function has no arguments, the reserved word 'void' is placed between the
parenthesis. Likewise, it is indicated with void that a function does not return any value (there is no
return statement). For example, the prototype function

void function (void);

does not return anything nor receives values.

When we want a function to return a string, the prototype is written

char *function (parameter list);

In the next chapter, we will study the meaning of the expression char * more deeply.

All programs that use functions from the standard library must include their
prototypes. These prototypes and other definitions used by the functions are in the files of
header comostdio.h, so the program must have the necessary #include statements.

Recursion

Recursion is a concept in mathematical logic that consists of defining a function in


terms of itself. For example, the definition of the factorial of a number is a recursive definition:
76 Introduction to the C Language

n! = n · (n - 1)!
0! = 1

In programming, a function is recursive if it can call itself. Not all languages


they allow recursion.Arecursive definition of a function requires two parts:

An exit condition or escape clause.


A step in which the remaining values of the function are defined based on defined values.
previously.

Recursion is an alternative to iteration. However, in general, a solution


recursive is less efficient, in terms of time, than an iterative solution. In addition, the solutions
Recursives use a lot of stack memory, as each function call causes it to be copied onto the stack.
(every time) all the game of arguments. This can create problems when reaching deep levels
of recursion. How to decide when a problem is solved recursively or through iterations
it depends on the problem itself. The recursive solution is usually the simplest, and it should be chosen if there is no
great speed requirements of the process nor problems with memory size. In another
we must choose the iterative solution, much faster, although often more complex.
The following function recursively solves the calculation of the factorial.

long factorial (int n)


{
if (!n) return 1;
return n * factorial(n - 1);
}

We will now represent the recursion process in a diagram when calling, for example, to
factorial(3).

factorial (3)

1st call to the function

3 * factorial (2) 3*2=6

2nd call to the function

2 * factorial (1) 2*1=2

3rd call to the function

1 * factorial (0) 1*1=1


Hereyoufindyourselfwiththe
exit condition
if (!n) return 1;

This process can be compared to that which generates the iterative solution:

long factorial (int n)


1. Introduction 77

{
register int i;
long total = 1;

for (i = 1; i <= n; i++) total *= i;


return total;
}
In the first case, several calls are made to the function, placing the corresponding values on the stack.
and "leaving pending" the intermediate calculations, until the exit condition is reached. In that
the moment the reverse process begins, pulling out the previously stored data from the stack and
solving the calculations that "remained unresolved." Obviously, this solution is slower than the
iterative in which the result is obtained with a single call to the function and with fewer requirements
by heart.

However, while in the case of calculating the factorial of a number it seems more
the iterative solution is advisable, there are other examples where the opposite occurs. For example, the
Ackermann function is defined as follows:

t + 1 s = 0
Ack  s, t = Ack  s - 1, 1 if s 0 and t = 0
Ack  s - 1   s 0yt 0

The recursive design of this function consists simply of applying the definition

int Ack (int s, int t)


{
if (!s) return t + 1;
else if (!t) return Ack (s - 1, 1);
else return Ack (s - 1, Ack (s, t - 1));
}

The non-recursive solution of theAckermann function is much more complicated.

The library of functions


There are a series of functions and macros defined by the ANSI standard that perform tasks that
greatly facilitate the work of the programmer. In addition, each software manufacturer includes its
own functions and macros, generally related to the better utilization of the
personal computers and MS-DOS. In this regard, it should be noted that compatibility
The code is only guaranteed if it exclusively uses functions belonging to the ANSI standard.
As mentioned before, the prototypes of these functions, as well as variable declarations, macros and
Data types used by them are defined in the header files *.h. Therefore, it is necessary
include them through statements #include when the program makes use of them.

The table on the next page shows the standard header files used by Turbo.
C++. Chapter 13 shows some of the functions of the standard library.
FILE
LANGUAGE DE DESCRIPTION
HEADER
78 Introduction to the C Language

ALLOC.H Define dynamic memory allocation functions


ANSI C ASSERT.H Declare the debug macro assert
C++ BCD.H Definetheclassbcd
BIOS.H Define functions used in ROM-BIOS routines
C++ COMPLEX.H Definecomplexmathematicalfunctions
C++ CONIO.H Define several functions used in the calls to
input/outputroutinesthroughconsoleinDOS
ANSI C CTYPE.H Contains information used by the macros of
conversionandclassificationofcharacters
DIR.H Containsdefinitionsforworkingwithdirectories.
DOS.H Declare constants and provide the necessary statements.
forspecificcallsofthe8086andDOS
ANSI C ERRNO.H Declare mnemonic constants for error codes
FCNTL.H Declare symbolic constants used in connections
withtheroutineslibraryopen()
ANSI.C FLOAT.H Containsparametersforfloating-pointroutines
C++ FSTREAM.H Define the C++ streams that support file I/O.
C++ GENERIC.H Containsmacrosforgenericclassdeclarations
C++ GRAPHICS.H Define prototypes for graphic functions
IO.H UNIXtypeI/Oroutinedeclarations
C++ IOMANIP.H Define the I/O stream managers of C++ and contains
macros for creating parameter managers
C++ IOSTREAM.H Define basic I/O stream routines of C++ (v2.0)
ANSI C LIMITS.H Parameters and constants about the capacity of the
system
ANSI C LOCALE.H Define functions about the country and language
ANSI C MATH.H Defineprototypesformathematicalfunctions
MEM.H Define the functions of memory management
PROCESS.H Contains structures and declarations for the
functionesspawn(),exec()
ANSI C SETJMP.H Statementstosupportnon-localjumps
SHARE.H Parameters used in functions that use
shared-files
ANSI C SIGNAL.H Declare constants and statements to use them in
function signal() and raise()
ANSI C STDARG.H Support for accepting a variable number of
arguments
ANSI C STDDEF.H Declareseveraltypesofdataandcommonlyusedmacros
ANSI C STDIO.H DeclaretypesandmacrosforstandardI/O
C++ STDIOSTR.H Declare the flow classes to use with structures
from stdin.h
ANSI C STDLIB.H Definesomeofthecommonlyusedroutines
C++ STREAM.H Define the flow classes of C++ to use with
bytearraysinmemory
ANSI C STRING.H Defineseveralstringmanipulationroutinesand
memory
SYS\STAT.H Declares symbolic constants used to open and
create files
SYS\TIMEB.H defines the function ftime() and the structure timeb.
C++ SYS\TYPES.H defines the type time_t
ANSI C TIME.H Structuresandprototypesfortimefunctions
VALUES.H Declaremachine-dependentconstants

Exercises
1. Introduction 79

1. The sine of an angle can be calculated using the series

you  x = x - x x+x
3 5 7
- +
3! 5! 7!

express in radians radians = 180 degrees). Write a program that calculates and
show on screen the sine of an angle using the previous series. Finish the calculation in the
the term of the series whose value is less than or equal to 10-3. For the calculation dexncreate a function no
prototypical recursive

double power (double x, int n);

Likewise, to calculate it, create a non-recursive function of prototype

double factorial (int n);

The angle must be a value between 0 and 360. In case, a message will be sent to
screen.

2. Write a program that calculates xpositive integers that are introduced by


keyboard. For the calculation, create a recursive function prototype.

long power(int x, int n);

thatIsolvethecalculation.

3. Write a program that shows the first N terms of the Fibonacci sequence.
using a recursive function

int Fibonacci (int N);

thatreturnstheelementN.ThevalueNwillbereadfromthekeyboard.

4. Write a program that displays the team information provided by the


library functions bioequip() and biosmemory().

5. Through the bioskey() function, create a program that displays the status on the screen of
keyboard keystroke in the following format:

Uppercase right: YES/NO


Uppercase left:YES/NO
Control Key: YES/NO
Alt key: YES/NO
Scroll Lock Key: YES/NO
Num Lock key: YES/NO
CapsLockkey: YES/NO
Ins key: YES/NO
80 Introduction to the C Language

NOTE: To avoid the effect that the cursor produces on the screen presentation (it is necessary to
continuously printing the information on the screen) remove it using the function
_setcursortype() from the standard library.

6. Write a prototype function

char *Intro (int f, int c, int size, char *string);

that I used the function cgets() to capture in row f, column c, a string of characters from
maximum length, and store it as a chain. Return each.

7. Write a prototype function

int strdigit (char *cad);

that I check the cadenacady returns1sicad is composed of numeric digits, and0if


some decadent character is numeric. Use the isdigit() function.

8. Write a prototype function

char *Format_date (char *date, int type, char *format);

that receives a date in DDMMAAAA format and places it in the string


format this date in a specified format by type. The allowed values by type and their
the corresponding formats are shown in the following table:

type format
0 DD/MM/YY
1 DD/MM/YYYY
2 DD of MMMMMMMMMM ofAAAA
3 dayoftheweek,DDofMMMMMMMMMMofAAAA

Sifechano is a valid date, or the type is out of range, the format will be the null string.
Return format. Use the sprintf() function.

9. Write a prototype function

int Validate_date (char *date);

that receives in the date chain a date in DDMMAAAAformat and returns a value from 0 to 6
if the date is correct, indicating with the values 0 to 6 the day of the week it corresponds to
date(0=sunday, 1=monday, ...). If the date is not correct, it will return -1. Use the function
Instructions to make calls to functions 2Ah and 2Bh of INT 21h.

10.Write a prototype function


int Key(int *scan);

that captures a key press and returns the scanning code, and through
return, its ASCII code. Use the bioskey() function.
1. Introduction 81

11.Write a prototype function


int Message (int st, int row, int col, char *str);

what presents on screen the chain chain the file file, column col. System value 1, wait for it to
press a key, returning its ASCII code if a normal key was pressed, and
1000 + exploration code if a special key was pressed. Sistvale0, does not wait for a key to be pressed.
no key.

Error! Marker not found


defined.
Matrices and pointers

What is a matrix?
A matrix is an internal data structure that stores a set of data of the same type.
type under a common variable name. The position of an element within the array comes
identified by one or more indexes, in such a way that each element is accessed by the name of
the matrix and its indices.

The dimension of a matrix is the number of indices needed to identify an element.

What are pointers?


A pointer is a variable that contains a memory address. For example, the
address of another variable.

Memory addresses
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
1393 date

The pointer stored at the position


from memory 1388 point to stored data
82 Introduction to the C Language

in memory position 1393

Pointer variables are declared as follows:

type *name;
being name the identifier of the pointer variable, and type the type of variable it points to.
For example,

char *m;
int *n;
float *p;

In these statements, the variables m, n are pointers that point, respectively, to data.
of type char, int or float. It is important to realize that you are not declaring a variable of type char, nor
the tipoint, nipde tipofloat. The types define the type of data that the pointer points to.

m 187 188 189 190 191 192 193 194


189
m points to a char data

n 187 188 189 190 191 192 193 194


189
n points to an int data

p 187 188 189 190 191 192 193 194


189
p points to a float data

The pointer operators are the ones we studied in Chapter 2, and they were defined in the
page 22, that is,

* &direction of
* at the address of

The operator can only be applied to pointers. After

float m;
float *p;
...
...
m = *p;

the variable mal stores the content of the address pointed to by p. Similarly after

*p = m;
The value is stored at the address pointed to by p. The following assignment
1. Introduction 83

int value = 100, q;


...
...
q = value;

it can also be achieved through

int value = 100, q, *m;


...
...
m = &value;
q = *m;

that is, the value 100 is stored in the variable.

The format code to display pointer variables using printf() functions is


%p. Thus,

int *m;
...
...
printf ("%p", m);

display the address stored in m. The display is in hexadecimal.


Another format code related to pointers is %n. This code results in the number of
characters that have been written at the moment it is located%n, are associated with a variable
whose address is specified in the argument list. The following program displays on the screen
the sentence

11 characters have been written

#include <stdio.h>
#include <conio.h>

void main (void)


{
int p;

clrscr ();
printf("Hello world %n", &p);
%d characters have been written
}

The allowed operations with pointers are:

Assignment
Increase / Decrease
Addition / Subtraction
Comparison
We are going to describe each of them.

Assignment
Given the statements
84 Introduction to the C Language

float x;
float *p, *q;

the way to assign the dexes address:

p = &x;
q = &x;

They both store the same memory address: that of the variable x. The same effect occurs.
achieve with direct assignment between pointers:

p = &x;
q = p;

A sentence like this is not correct.

p = x;

since you are a variable of type float (stores a float data), while storing it
direction of a float type data.

Through pointers, content assignments can be made. For example:

float a, b;
float *p, *q;
...
...
a = 1.5;
p = &b;
q = &a;
*p = *q;

In this sequence, they store different values (the address of and the address of
a, respectively). The last statement assigns contents, that is, it stores in the place
pointed by p (variable b) what is at the location pointed by q (variable a). It is, therefore,
equivalent to

b = a;

Increase / Decrease

To understand these operations, we must take into account that they refer to
memory elements and not addresses. This means that the ++ and -- operators act on
different mode depending on the type pointed to by the pointer. You have a pointer to characters (char *p) the
operation p++ increases the value of pen1. However, if you have a pointer to integers (int *p),
the same operation p++ increments the value of pen2 to point to the next element,
Well, the type 'point' occupies two bytes. Similarly, for the type 'float', the operation 'p++'
increase the value of depen4.

The same applies to the operator--, but with decrementing, for the
operator--.

Addition / Subtraction
1. Introduction 85

The same thing happens with increment and decrement operations. Yup
it is a pointer, the operation

p = p + 5;

makes it point 5 elements beyond the current one. It was defined as a pointer to
characters, its value will increase by 5, but if it was defined as a pointer to integers, it
will increase by 10.

Comparison

Pointers can be compared in the same way as any other variable, having
always present that addresses are compared and not contents.

int *p, *q;


...
...
if (p == q) puts("p and q point to the same memory position");
...
...
if (*p == *q) puts("The positions pointed to by p and q store the same value");

In the second case, the message may appear even though they point to different addresses.

One-dimensional matrices

They are those that only require an index to access each element. They are also called
solo vectors.

All elements of a vector are stored in contiguous memory locations.


storing the first element at the lowest address.

Avector is declared in the following way:

typename[num_elem];

determine the data type of all the elements of the vector, name is any valid identifier
C, ynum_elemes the number of elements of the vector. For example,

char phrase[20];
int number[16];
float value[12];

They declare, in this order, a vector of 20 characters, another of 16 integer elements, and another of 12.
floating point elements. The number of bytes occupied by an array is calculated by multiplying the
number of elements by the size of each of them. Thus, the 3 previous vectors occupy,
respectively, 20, 32, and 48 bytes.

In matrix declarations, the name of the matrix without indices is a pointer to the first
element. Thus, in the previous statements, a pointer stores the address of
The same happens for number and value.
86 Introduction to the C Language

In a vector of N elements, the first is referenced with index 0 and the last with index.
N-1. Thus, in the vector

int number[16];

the first element is number[0] and the last number[15].

It is important to note that C does not perform boundary checks in the array process.
The control must be done by the programmer. Thus, it is possible to write

number[30] = 250;

handling the 30th element of the vector number that was declared to store only 16 elements. The
consequences for the program tend to be disastrous.

In the following program, a vector of 10 characters is loaded from the keyboard and displayed.
after the address and content of each element.

Error! Marker not defined.#include <stdio.h>


#include <conio.h>

void main (void)


{
register int i;
charvector[10];

for (i = 0; i <= 9; i++) vector[i] = getche();

for (i = 0; i <= 9; i++) printf ("\nPlace: %d -Address: %p - Value: %c", i, vector + i, vector[i]);
}

Character strings
A particular case of a vector is the string of characters. A string of characters is declared
by means of

char name[num_car];

and allows to store num_car-1 characters and the null character '' for termination. Therefore, a
statement as

char sentence[21];

it is suitable for storing 20 characters and the null.

C allows the initialization of character strings in the declaration, through statements of


type

This is a string of characters

in which it is not necessary to add the final null or indicate the size, as it does so automatically
compiler.
1. Introduction 87

Operations with strings of characters such as copying, comparing, concatenating, measuring, etc., are
are made using functions from the standard library. Their use requires including the file
headerstring.h. Let's see some of them.

char *strcat (char *string1, const char *string2);

Concatenating acad2 to acad1 returning the address of acad1. Remove the null termination of
initialcad1

Example:

char cad1[80], cad2[80];


...
...
Type a phrase:
gets (cad1);
Type another sentence:
gets (cad2);

strcat (cad1, cad2);


puts (cad1);

In this example, if you typeFirst sentenceforcad1andSecond sentenceforcad2, it is displayed in


screen

First sentenceSecond sentence

It would have the same effect.

puts (strcat (cad1, cad2));

One must ensure that the size is adequate to store the result.

char *strchr (const char *cad, int ch);

Returns the address of the first occurrence of the character in the string. If not
find returns a null pointer.

Example:

char *p, character, string[80];


int place;
...
...
Type a character:
character = getche();
Type a phrase:
gets (string);

p = strchr (string, character);


The character %c is not in the sentence
else {
place = p - string;
The character %c occupies the place %d in the sentence
88 Introduction to the C Language

int strcmp (const char *str1, const char *str2);

The use of operators > for string comparison is not allowed.


instead of using <, >=, !=, etc., the strcmp function should be used. This function compares lexicographically
cad1ycad2y returns an integer that should be interpreted as follows:

<0 cad1 < cad2


0 cad1 equals cad2
0 cad1 > cad2

Example:

char cad1[40], cad2[40];


...
...
Type a phrase:
gets (cad1);
Type a phrase:
gets (cad2);

n = strcmp(cad1, cad2);
If (!n) puts ("They are equal");
else if (n < 0) puts ("The first is less than the second");
else puts ("The first is greater than the second");

It is necessary to insist that the comparison is not made in terms of the size of the chain but in
as for the order of characters in the ASCII code. This means that sicad1esABCDEycad2
esxyz, the strcmp function returns a negative value, as it is considered that cad1 < cad2 since the
Character A has an ASCII code less than character x.

char *strcpy (char *dest, const char *src)

Copy the chain cad2 over cad1, overwriting it. Return the address of cad1. There is a need to
ensure that the size deca1 is sufficient to accommodate acad2.

Example:

char string[40];
...
...
strcpy (string, "Good morning");

int strlen (const char *str);

Returns the number of characters stored (excluding the null terminator).

Example:
1. Introduction 89

char cad[30];
...
...
Type a phrase:
gets (cad);
The phrase <<<%s>>> has %d characters

char *strlwr (char *str);

Convert all to lowercase. The function has no effect on characters that are not letters.
upper case. It also has no effect on the extended set of ASCII characters (code greater than
127), so it does not convert the letters Ñ, Ç, or accented vowels. It returns the address dec.

Example:
char cad[40];
...
...
Print a phrase in uppercase:
gets (cad);
The lowercase string is %s

char *strrev (char *str);

Invert the cadenacady returns its address.

Example:

char cad[80];
...
...
Type a phrase:
gets (cad);
Reversed phrase: %s

char *strset (char *cad, int ch);

Replace each of the characters dec with the character ch. Return the address dec.

Example:

char cad[80];
...
...
strcpy(cad, "12345");
strset (cad, 'X');
A string with 5 X is displayed
puts (cad);

char *strupr (char *str);


90 Introduction to the C Language

Convert each uppercase. The function has no effect on characters that are not letters.
lowercase letters or the extended set of ASCII characters (letters ñ, ç or accented vowels).
Return the decadent address.

Example:

char cad[40];
...
...
Type a phrase in lowercase:
gets (cad);
The phrase in uppercase is %s

Chapter 13 shows more string functions.

There is also a wide range of functions that handle individual characters. The
most of these functions report the type of character included in their argument by returning a
value 1 or 0. These functions have their prototype defined enctype.hy and generally do not consider the
extendedASCII set. Some of these functions are explained below:

int isalnum(int ch) Return 1 alphanumeric character (letter of the alphabet or digit) and 0 otherwise.
opposite.

int isalpha (int ch) Return 1 if it is a letter of the alphabet and 0 otherwise.

int isdigit (int ch) Returns 1 if a digit from 0 to 9, and 0 otherwise.

int islower (int ch) Devuelve 1 siches un letra minúscula y 0 en caso contrario.

int isupper (int ch) Devuelve 1 siches una letra mayúscula y 0 en caso contrario.

int tolower (int ch) Return the lowercase character. If it is not an uppercase letter then
functionreturnswithoutmodification.

int toupper(int ch) Return the uppercase character. If it is not a lowercase letter, the
functionreturnchsinwithoutmodification.

Chapter 13 shows more character functions.

The following program uses some of the previous functions to examine a string
of characters and convert lowercase to uppercase and vice versa. It also counts how many characters
they are numeric digits.

Error! Marker not defined. #include <stdio.h>


#include <conio.h>
#include <string.h>
#include <ctype.h>

void main (void)


{
charstring[100];
int counter = 0;
register int i;

clrscr();
Type a string of characters:
1. Introduction 91

gets (string);

for (i = 0; i <= strlen (string); i++) {


if (isupper(cadena[i])) cadena[i] = tolower(cadena[i]);
else if (islower(cadena[i])) cadena[i] = toupper(cadena[i]);
else if (isdigit (cadena[i])) counter++;
}
The string has %d numeric digits
puts (string);
}

Pointers and arrays


Since a matrix is identified by the address of the first element, the relationship
The relationship between pointers and arrays is close. Let the declaration be

int array[100];

We can identify an element, let's say 25, in either of the following two ways:

matrix[24];
*(matrix + 24);

the address of the first element.

The use of pointers to handle arrays is generally more efficient and faster than using
of indexes. The decision on which method to use (pointers or indexes) depends on the type of access. If
Accessing the elements of the array randomly, it is better to use indices. Without
embargo, if access is going to be sequential, it is more appropriate to use pointers. This second case is the
typical in character strings. For example, the following statements display on the screen,
character by character a string of characters.

char *p, string[30];


register int i;
...
...
for (i = 0; string[i]; i++) putch (string[i]);
...
...
p = string;
for (; *p; p++) putch (*p);
...
...
p = string;
while (*p) putch(*p++);

The last two are the most suitable. Another example consists of the 3 functions that are
described below. These functions compare two strings in a manner similar to
how do you do strcmp()?

int compare1 (char *str1, char *str2)


{
92 Introduction to the C Language

register int i;

for (i = 0; cad1[i]; i++) if (cad1[i] - cad2[i]) return (cad1[i] - cad2[i]);


return 0;
}

int compare2 (char *str1, char *str2)


{
char *p1, *p2;

p1 = cad1;
p2 = cad2;

while (*p1) {
if (*p1 - *p2) return (*p1 - *p2);
else {
p1++;
p2++;
}
}
return 0;
}

int compare3 (char *str1, char *str2)


{
char *p1, *p2;

p1 = cad1;
p2 = cad2;

for (; *p1; p1++, p2++) if (*p1 - *p2) return (*p1 - *p2);


return 0;
}

Of the 3 previous functions, the last two are more efficient.

Two-dimensional matrices

A two-dimensional matrix is one that requires two indices to identify an element.


It can be said that a two-dimensional matrix is a data structure organized in rows and columns.
They are declared as follows:

type name[number of rows][number of columns];

For example, to declare an array of integers organized in 8 rows and 6 columns, one
write

int total[8][6];
1. Introduction 93

The first element of the matrix estotal[0][0] is stored in a memory address identified
portal. The last is total.

A particular case of two-dimensional matrices consists of string matrices.


characters. For example, the statement

char cadenas[10][25];

declare a matrix of 10 strings of 24 characters plus the null. To access a specific string
just specify the left index (string number). Thus,

gets (string[6]);

reads a string of characters from the keyboard and stores it in the seventh string (the first string is [0])
from the matrix. This statement is equivalent to

gets (&cadena[6][0]);

To access a specific character of a string, both indices must be specified. For


example, the sentence

store the characterX in the 10th character of the 4th string.

Error! Marker not defined.//Change the vowels to # in a group of strings.


#include <stdio.h>
#include <conio.h>
#include <string.h>

void main(void)
{
char string[10][70];
register int i, j;

clears the screen ();

for (i = 0; i <= 9; i++) {


String number %d:
gets (string[i]);
}
for (i = 0; i <= 9; i++) {
for (j = 0; string[i][j]; j++) {
if (strchr ("aeiouAEIOU", cadena[i][j])) cadena[i][j] = '#';
}
puts (string[i]);
}
}
In the following program, a matrix of 10 strings is loaded from the keyboard and searched.
in them the first appearance of the chain HOLA, informing about the chain number in which it
finds and the position it occupies in it. For this, the function strstre explained in the
Chapter 13 (page 212).

Error! Marker not defined.#include <stdio.h>


#include <conio.h>
94 Introduction to the C Language

#include <string.h>

void main (void)


{
chararray[10][50];
register int i;
char *p;

clearscreen();
for (i = 0; i <= 9; i++) {
String number %d:
gets (string[i]);
strupr(cadena[i]);
}

for (i = 0; i <= 9; i++) {


p = strstr (string[i], "HELLO");
if (p) printf ("\nString no %d, position %d", i, p - string[i]);
}
}

We can access the elements of a two-dimensional array using pointers. We


access the element matrix[i][j] using the formula:

(matrix + i * number_of_rows + j)

Matrices of more than 2 dimensions

In C, arrays of more than 2 dimensions can be handled. To declare these arrays, it is done

type name[size 1][size 2] ... [size N];

The following statement declares a three-dimensional array of float type elements:

float matriz3D[5][3][8];

The problem with this type of matrices is the amount of memory they can occupy.
which increases exponentially with the number of dimensions. That is why for these
structures usually use dynamic memory allocation, allowing assigning or trimming
memory as needed. We will study this in Chapter 9.

The following statements show how to load the 3D array from the keyboard.

for (i = 0; i <= 4; i++) {


for (j = 0; j <= 5; j++) {
for (k = 0; k <= 7; k++) {
Element %d-%d-%d:
scanf("%f", &matriz3D[i][j][k]);
}
}
}
1. Introduction 95

How to initialize matrices

Any matrix can be initialized at the time of declaration. To do this, they are enclosed
in brackets, separated by commas, the initialization data. Let's see some examples:

float vector[5] = {1.23, 16.9, -1.2, 2.06, 31.15};


int table[2][3] = {5, 62, 34, 21, 43, 90};

For more clarity, in two-dimensional matrices it is common to do:

int table[2][3] = { 5, 62, 34,


21, 43, 90

In the last two cases, the matrix table is initialized as follows:

tabla[0][0] = 5 tabla[0][1] = 62 tabla[0][2] = 34


table[1][0] = 21 tabla[1][1] = 43 tabla[1][2] = 90

The same effect is achieved using key nesting:

The provided text is not a translatable sentence. It appears to be a programming code snippet.
Invalid input for translation

Character string arrays can be initialized in the following way

char frases[3][30] = { "Primera cadena", "Segunda cadena", "Tercera" };

In all multidimensional arrays, the first index can be omitted when they are initialized.
in the statement. Therefore, the following statements:
int table[3][4] = { 6, 12, 25, 4, 5, 13, 7, 2, 2, 4, 9, 6};
int table[ ][4] = {6, 12, 25, 4, 5, 13, 7, 2, 2, 4, 9, 6};

They are identical. In the second case, the compiler takes care of calculating the corresponding size.

Matrices as function arguments

When an array is passed as an argument to a function, the compiler generates the call
with the address of the first element. This way, passing the entire array is avoided, which consumes
a lot of memory and slows down the process. Let's say, for example, the one-dimensional array

int vector[30];

that is intended to be passed as an argument to a greater() function that returns as its return value the
largest element of the matrix. The call is made in the following way

a = mayor (vector);

and the function mayor() can be declared in any of the following ways:
96 Introduction to the C Language

int mayor (int x[30]) int mayor(int x[])


{ {
... ...
... ...
} }

In either case, the result is identical, as both statements indicate to the


compiler that will receive as an argument the address of an integer (the one of the first element of the
matrix). In the first case, the value 30 is not taken into account.

The following program loads a matrix of integers from the keyboard and displays the largest of them.
calculating it through a function.

Error! Marker not defined.

void main (void)


{
register int i;
int vector[30];

for (i = 0; i <= 29; i++) {


Element %d:
scanf ("%d", &vector[i]);
}
printf ("\nThe largest is %d", largest (array, 30));
}

int max(int array[], int num_elements)


{
register int i;
int max;

table[0];
for (i = 0; i < num_element; i++) if (max < tabla[i]) max = tabla[i];

return max;
}

Note that it is necessary to pass the size of the matrix as an argument; otherwise, the
functionGreater() would not have any information about the number of elements in the array.

For two-dimensional arrays, even though only the address of the first element is passed, it is
it is necessary to specify the number of columns (second index) so that the compiler knows the length
from each row. For example, a function that receives a matrix declared as

int matriz2D[10][20];

is declared as follows:

function (int x[][20])


{
...
1. Introduction 97

and the call is made with a statement such as

function (2Dmatrix);

In general, for multidimensional arrays, only the first index can be omitted in the
declaration. For example, an array declared by

int matriz3D[5][10][20];

it is passed as an argument to a function through a call in the form

function (3Dmatrix);

and the function declaration looks like this:

function (int x[][10][20])


{
...
}
Arguments of the main() function

When, for example, we write an order from the DOS prompt like

C:\>XCOPY *.DAT B: /S

We are running a program called XCOPY.EXE with 3 parameters: *.DAT, B:y/S. Those
parameters, in some way, are read by the program XCOPY.

To do this in any C program, it is necessary to modify the way it is called.


main function(), including in it arguments that allow for the obtaining of parameters
Introduced in the command line. The way to do this is as follows:

main (int argc, char *argv[ ])

Let's see the meaning of the variables argcy argv.

argc: Integer that indicates the number of parameters typed (includes the name of the
program.
argv[]: Array of character strings. Each of the elements argv[i] is a string.
that stores an argument.

The variable argc is worth at least 1, since the name of the program is counted.
parameters are identified through argv in the following way:

argv[0] string that stores the name of the program.


argv[1] string that stores the first parameter.
argv[2] string that stores the second parameter.
...
...
argv[argc] is zero (In reality, it is a null pointer).

For the arguments to be treated as different, they must be separated by one or more.
white spaces. Thus, in the previous example the variable argc is 4 (program name and 3
parameters). If we write, for example
98 Introduction to the C Language

C:\>PROG PAR1,PAR2

the variable argc would be 2, since the string PAR1,PAR2 is identified as a single
parameter (stored in the string argv[1]) since the comma does not act as a separator. In order to
PAR1 and PAR2 should be treated as two different parameters; PROG must be executed through

C:\>PROG PAR1 PAR2

The following program lists the parameters, if any, of the command line.
#include <stdio.h>

void main (int argc, char *argv[ ] )


{
register int i;

Program name: %s
No parameters have been provided
else {
Parameters in the command line:
for (i = 1; i < argc; i++) printf ("\n%d: %s", i, argv[i]);
}
}

The main() function supports one more variable, called env:

env[]: Array of character strings. Each element of the array is a string


that stores the name and content of an environment variable.

#include <stdio.h>

void main (int argc, char *argv[ ], char *env[ ])


{
register int i;

Program name: %s
if (argc == 1) printf ("\nNo parameters have been entered");
else {
Command line parameters:
for (i = 1; i < argc; i++) printf ("\n%d: %s", i, argv[i]);
}

Environment variables:
for (i = 0; env[i]; i++) puts (env[i]);
}

If this program is compiled and linked as PROG.EXE and is run as

C:\>PROGRAM PARAM1 PARAM2 C:\> PROG


provide the output
PROG PROG
Parameters in the command line: Noparametershavebeenintroduced.
PAR1 Environment variables:
1. Introduction 99

2:PAR2 C:\DOS\COMMAND.COM
Environment variables: PROMPT=$P$G
C:\DOS\COMMAND.COM
PROMPT=$P$G
PATH=C:\;C:\DOS;C:\WINDOWS
Pointer matrices
Pointer arrays can be defined, that is, arrays whose elements are addresses.
For example,

int *pint[20];
char *pchar[40];

declare a matrix pint of 20 pointers to integers and another matrix pchard of 40 pointers to
characters.

To assign the addresses, it is done the same way as with any other pointer. Using the
following sentences

int *pint[20], a;
...
...
a = 20;
pint[3] = &a;
printf ("%d", *pint[3]);

the number 20 is displayed on the screen.

A typical example of a pointer array is the array of character strings. The


the following statements are equivalent

char dias[ ][10] = { "Domingo", "Lunes", "Martes", "Miércoles",


Thursday

char *dias[ ] = { "Domingo", "Lunes", "Martes", "Miércoles",


"Jueves", "Viernes", "Sábado" };

Pointers to pointers
In most cases, a pointer points to a data.

p x
Address
of Valor
x

y* provides the value of dex. But you can also define pointers to pointers.
100 Introduction to the C Language

p1 p2 x
Address Address
of of Value
p2 x

In this case, p2 provides the value of x. But p1 provides the address of p2. For
access through p1 you need to do **p1.

#include <stdio.h>

void main (void)


{
int x, *p, **q;

x = 10;
p = &x;
q = &p;

printf ("%d", **q);


}

This program displays the number 10 that it stores.

Pointers to functions
Since a function occupies a position in memory, pointers can be defined to
functions, and making calls to the function through the address. This generally applies
to work with arrays of functions. Let's see it with an example. The following program performs
the basic operations addition, subtraction, and multiplication, through function calls that form
part of a matrix.

#include <stdio.h>
#include <conio.h>

int menu (void);


int sum(int, int);
int subtract(int, int);
int product (int, int);

int (*calculation[3]) (int, int) = { sum, subtract, product };


void main (void)
{
int n, x, y, result;

while (( n = menu()) != 3) {
Type two numbers:
1. Introduction 101

scanf("%d %d", &x, &y);

result = (*calculation[n])(x, y);


printf (" = %d", result);
getch();
}
}

int menu (void)


{
int option;

clrscr ();
0. Sum
1. Subtract
2. Product
3. Exit

do {
option = getch();
} while (option < '0' || option > '3');

return option - 48;


}

int sum(int a, int b)


{
%d + %d
return a + b;
}

int subtraction (int a, int b)


{
%d - %d
return a - b;
}

int product (int a, int b)


{
%d * %d
return a * b;
}

In general, a pointer to a function is declared according to

type (*pfunc) ();

being the name of the pointer, and type the type of the value returned by the function. The
parentheses are necessary, because

type *pfunc();

declare a function that returns a pointer. To call the function, it must be done

(*pfunc) ();
Introduction to the C Language

Exercises

1. Load an integer matrix of 4 rows and 3 columns using the keyboard. Calculate and display in
display the sum of each row and each column through two prototype functions

int sum_row(int row);


intsum_column(intcolumn);

2. Build a program that creates and displays a magic square of order 3. A


A magic square is one in which all the rows and columns sum to the same value. To do this, one must
place the value 1 in the middle of the 1st row. The following values (2, 3, 4, ...) are positioned in the row
from above, right column, unless it is occupied, in which case it is placed
immediately below. The rows and columns at the ends are supposed to be adjacent.

1 1 6 8 1 6
3 3 5 3 5 7
2 4 2 4 9 2

3. Build a program that creates and displays an odd-order magic square.


(3 < N 19). The value of N will be read from the command line (declaring it appropriately)
main function). Displays an error message on screen in each of the following cases:

The value of Nest is out of range.


No value has been given in the order line.
There are too many parameters in the command line.

In any case, you will end the program after sending the message. (NOTE:
Use the atoi() function from the standard library.

4. Build a program that loads two integer matrices A and B of order 3x3 from the keyboard, and that
visualize the matrix productP =A· B.

3
p ij ab
I kj
k 0

You must load the matrices using a function that you will call twice: once
to load A. Also, you will calculate the elements B.ijthrough a function.

5. Build two similar functions astrlwr() and strupr() that also act on the characters.
ñ, ç, accented letters, etc. They will be called strminus() and strmayus().

6. Develop the following functions:

A function called bubble() that sorts an array of 100 in ascending order.


integer elements by the bubble method.
1. Introduction 103

A function called selection() that sorts a vector of 100 in ascending order.


integer elements by the selection method.
A function called insertion() that sorts a vector of 100 in ascending order.
integer elements by the insertion method.
A function called shell() that sorts an array of 100 in ascending order.
integer elements by the shell method.
A function called quick() that sorts a vector of 100 in ascending order.
integer elements by the quick sort method.

Build a program that loads a vector sorted in descending order.

a[0] = 99 a[1] = 98 a[2] = 97 ... a[99] = 0

and determine, through calls to the previous functions, which sorting method is
faster. To measure the time, use the function from the standard library biostime() whose
prototype is in bios.h.

7. Build two prototype functions


char *Copy (char *str1, const char *str2);
char *Concatena (char *cad1, const char *cad2);

that perform the same operations, respectively, as the library functions


standard strcpy() and strcat(). Make two versions of each function: one with indexes and the other with
pointers.

8.Build a prototype function


char *Insert (char *str, int ch, int position);

that inserts the character in the position of the string. The function must return the
decad address. Make two versions of the function: one with indexes and another with pointers.

9. Build a prototype function


char *Delete (char *str, int pos);

to remove the character located at position pos. The function should return the
decad address. Create two versions of the function: one with indices and another with pointers.

10. Build a prototype function


char *Substr (char *orig, int from, int n, char *dest);

that stores in the string the substring that begins at the position
it has characters. The function must return the address of dest. Make two versions of the
function: one with indices and another with pointers.

11. Create a vector of 1000 integer elements ordered in descending order:


Introduction to the C Language

x[0] x[1] x[2] ... x[998] x[999]


999 998 997 ... 1 0

and sort it in ascending order using the bubble method. Make two versions of the program:
one with indices and another with pointers. Measure the efficiency of each method using the
standard library function clock()

12. Using pointers, load a vector of 50 integer elements (Generate the values
randomly through the functions of the standard library random() and randomize().
Subsequently, it shows what the highest value is, its position in the vector, and the position of
memory it occupies.

13.Create a program that creates an array ready to store 50 integer data.


function with stack structure. The program will perform the following actions:

Show the contents of the stack.


Insert a data into the stack.
Remove a data from the stack.
End of the program.

The program will present this menu and perform the desired actions through functions.
grouped in a matrix.

8
Other types of data

Introduction

The C Language allows the user to create new data types using 5 tools:

The typedef statement, which allows giving new names to existing data types.
Structures are groupings of variables of different types under a common name.
Bit fields, which are a variant of structures, allow access
individual to the bits of a word.
Unions, which allow assigning the same memory area for variables
different.
Enumerations, which are lists of symbols.

We will study each one of them below.


1. Introduction 105

User-defined types

Through the typedef reserved word we can give new names to data types that
They already exist. The syntax is as follows:

typedef type name;

dondetipoes a data type and nombrees is the new name for the previous data type. For
example:

typedef register int COUNTER;

makes C recognize COUNTER as a data type identical to register int. Thus, after
From the previous definition, we can declare variables of the new type using statements such as

COUNTER i, j;

that declares two variables i, j of type COUNTER, that is, register int. Furthermore, this type of
definitions do not override the previous type, so we can continue declaring variables of that type
register intque live together with statements of type COUNTER.

Through this statement, we can use more convenient names for data types, and
make the source code clearer.

Structures

A structure is a set of variables of the same or different type, grouped under a


common name. These variables are called fields of the structure. Structures are
they declare using the reserved word struct. There are various ways to declare a structure, but
the most general is the following:

structname_structure{
type variable1
type variable2;
...
...
type variableN;
};

Let's see an example. The following statement

struct FICHA {
char name[40];
int age;
float height;
};

define una estructura llamadaFICHAcon tres campos de distinto tipo:nombre,edadyaltura.


106 Introduction to the C Language

We must take into account that the previous statement only defines the shape of the structure,
but it does not declare any variable in that form. So to speak, we have defined a template
of 3 fields, but we have not applied this template to any variable. To do so, it is necessary to
write sentences like

struct FICHA record;

that declares a variable called registro with the structure FICHA, that is, registro is a
variable composed of 3 fields: name, age, and height. To access each of them
fields use the dot (.) operator as follows:

strcpy(registro.name, "José García");


registro.edad = 38;
registro.altura = 1.82;

Of course, multiple variables can be declared with the same structure:

struct FICHA var1, var2;

What are two variables with the structure FICHA. The fields of each of them, such as
ejemplovar1.age and var2.age are two different variables that occupy memory positions.
different.

Variables can also be declared at the same time as the structure is defined:

struct FICHA {
char name[40];
int age;
float height;
} var1, var2;

that declares two variables var1 and var2 with the FICHA structure. This type of declaration does not
it prevents declaring more variables with that structure:

The text provided is not in a translatable format.

struct FICHA {
char name[40];
int age;
float height;
} var1, var2;

void Function (void);

void main (void)


{
struct FICHA var3;
...
...
}

void Function (void)


{
struct FICHA var4;
...
...
}
1. Introduction 107

In the previous statements, 4 variables are declared with the FICHA structure: var1 and var2.
global; var3, local main(); and var4, local aFunction().

Declarations of a structure can be made without giving it a name. For example:

struct {
char name[40];
int age;
float height;
} var1, var2;

declare variables var1 and var2 with the indicated structure. The problem posed by this type of
the statements is that, without having a name for the structure, it is not possible to declare other variables with
that structure.

It is also common to define structures with a new type. For example:

typedef struct {
char name[40];
int age;
float height;
} MIESTR;

Now we can make use of the new type to declare variables using statements like:

MIESTR var1, var2;

Let's note that, due to the typedef statement, MIESTR is not a variable, but a type.
of date.

Initialization of structures

It is possible to initialize variables with structure at the time they are declared. For
example:

Invalid input: code snippet detected.

struct FICHA {
char name[40];
int age;
float height;
};

void main (void)


{
José García
...

that produces the same effect as the sentences

strcpy (record.name, "José García");


registro.edad = 38;
registro.altura = 1.82;
Nesting of structures
Introduction to the C Language

Nesting of structures is possible, in the sense that a field of a structure


it can also be a structure. Let's see it with an example:

struct DATE {
int day;
int month;
int year;
};

struct CUMPLE {
char name[40];
struct DATE birth;
};

struct CUMPLE anniversary;

The anniversary variable as defined has the following fields:

anniversary.name
birthday.celebration.day
birthday. birth. month
birthday.year

Nesting of structures can be done to a greater depth, in which case access to


The fields of the variable are made using dot operators successively.

Structure matrices

One of the most common uses of structures is arrays. To declare a


The matrix of a structure is made like for any other variable. For example,

struct FICHA {
char name[40];
int age;
float height;
};
...
...
struct FICHA vector[100];

declare a vector of 100 elements called vector. Each of the elements vector[i] is
formed by the 3 fields defined in the structure. The fields of the element 'vector' are:

vector[i].name
vector[i].age
vector[i].height
If any of the fields in the structure is an array (as is the case with the field
name) each element can be accessed in the following way:

vector[10].name[3]

which refers to the character 3 of the fieldname of the elementvector[10].


1. Introduction 109

Transition from structures to functions

A field of a structure can be passed as an argument to a function of the same structure.


way that any simple variable. The following program displays on the screen, by means of a
function, a field of a structure.

#include <stdio.h>
#include <conio.h>

struct FICHA {
char name[40];
int age;
float height;
};

void Function(int);

void main (void)


{
José García

clearscreen();
Function (record.age);
}

void Function(int n)
{
Age: %d
}

You can also pass the address of a field of a structure. A similar program
to the previous one, but managing the direction of the field, it is as follows:

#include <stdio.h>
C includes a conio header.

struct FICHA {
char name[40];
int age;
float height;
};
void Function (int *);

void main (void)


{
José García

clear screen();
Function (&record.age);
}

void Function (int *n)


{
Introduction to the C Language

printf ("\nAge: %d", *n);


}

Finally, we can also pass the complete structure as an argument to a


function. The following example shows how to do it:

#include <stdio.h>
#include <conio.h>

struct FICHA {
char name[40];
int age;
float height;
};

void Function (struct CARD);

void main (void)


{
struct FICHA registro = { "José García", 37, 1.82 };

clear screen();
Function (record);
}

void Function (struct FICHA n)


{
Function3
Name: %s
Age: %d
Height: %f
}

Pointers to structures

When the structures are complex, the transition from the complete structure to a function
it can slow down the programs due to the need to input and output all the time
elements of the structure in the stack. That is why it is advisable to resort to passing only the
address of the structure, using pointers.
A pointer to a structure is declared in the same way as a pointer to any other.
variable type, using the operator *. For example, the statement

struct MIESTR *p, var;

declare a pointer to a structure and a variable with that structure. After


A statement like the one above can be assigned as follows:

p = &var;

that assigns the address of the variable var.

To access the fields of the structure via the pointer, it is done

( *p ).field
Introduction 111

However, this syntax is old and out of use. Instead, the operator is used.
arrow (->), formed by the dash (-) and the greater than symbol (>).

field

The following program displays the fields of a structure on the screen through a
pointer that contains its address.

#include <stdio.h>
#include <conio.h>

struct FICHA {
char name[40];
int age;
float height;
};

void main (void)


{
struct FICHA *p, record = { "José García", 37, 1.82 };

clear screen();
p = &record;
Name: %s
Age: %d
Height: %f
}

Bit fields

Bit fields are a special case of structures that allow access to bits.
individuals of a word. The syntax that defines a bit field is as follows:
structstructure_name{
variable1 type:width1;
variable2 type:width2;
...
...
type variableN:widthN;
};

do not type one of the types char, unsigned char, int or unsigned int, and wide is a value of
0 to 16, which represents the width in bits of the variableN bit field. If no name is given to the
bit field, the specified bits are reserved but not accessible.

The following example shows a bit field declaration:

struct MIESTR {
int i: 2;
unsigned j: 5;
int : 4;
int k: 1;
unsigned m: 4;
};
Introduction to the C Language

struct MIESTR var;

This statement corresponds to the following word design:

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

m k not used j i

Bit fields are useful for storing logical variables in a byte, for encoding
the bits of a device, etc. Access to the bit fields is done in the same way as to the
fields of any structure. You only need to keep in mind a couple of restrictions with the
bit fields: arrays are not allowed and working with addresses is not possible.

Bit fields can pose some problems regarding the portability of the
programs from one machine to another. It has been assumed that the fields operate from left to
right, but that may change on other machines, with what the interpretation of the different
fields change.

Unions

A union is a grouping of variables that occupy the same memory position.


they declare in a manner similar to the structures:

unionname_union{
type variable_1;
type variable_2;
...
...
type variable_N;
};

When a union is declared, the variables variable_1, variable_2, ..., variable_N occupy
the same memory position. The compiler reserves enough space to store the
bigger variable.

It is important to note a significant difference between structures (struct) and unions.


(union). In the first, each field occupies its own memory position, and when it
stores a value in one of the fields, it does not affect the rest. On the contrary, in the unions
all the variables of the union have the same memory position assigned, which implies
that when a piece of data is stored in one of them, it affects all the others. Let's clarify this with
a simple example. Let the structure

struct MIESTR {
char a;
int b;
float c;
};
1. Introduction 113

struct MIESTR mivar;

This statement allocates 7 bytes of memory for the variable mivar: one for the field a,
two more for the campob, and another four for the campoc.

mivar

6 5 4 3 2 1 0

c b a

If we make an assignment like

mivar.b = 120;

does not affect amivar.ani amivar.c, since each of them has assigned different addresses.
memory.

However, it is the union

union MIUNION {
char a;
int b;
float c;
};

union MIUNION mivar;

This statement allocates 4 bytes of memory for var (the largest field of the union
esc, of 4 bytes).

mivar

3 2 1 0

If we now make an assignment such as

mivar.b = 120;
Introduction to the C Language

it affects both amivar.a and amivar.c.

Let’s see an example. The following statements use structures and unions to
store data of 100 students and teachers of an Educational Center. The type is stored
Name, age, address, and phone. If it is a student, it is also stored,
the group to which he/she belongs, the number of subjects he/she is taking, and whether he/she is a repeat student or not. If he/she is a teacher

the registration number and the position held are stored.


1. Introduction 115

struct STUDENT {
char group[15];
int assigned;
char repeat;
};

struct PROFESSOR {
char nrp[16];
char cargo[21];
};

union AL_PR {
struct STUDENT al;
struct PROFESSOR pr;
};

struct DATA {
char type;
char name[40];
int age;
char address[40];
char phone[8];
union AL_PR both;
} personal[100];

The following program segment displays the data of the personal matrix.

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


Name: %s
Age: %d
Address: %s
Phone: %s
if (personal[i].type == 'A') {
STUDENT
Group: %s
Number of Subjects: %d
Repeat: %d
else {
PROFESSOR
N.R.P.: %s
Position: %s
}
}

By combining structures, unions, and bit fields, we can define 16-bit variables.
with access by bit, byte or word.

struct BITS {
unsigned bit0: 1;
unsigned bit1: 1;
unsigned bit2: 1;
unsigned bit3: 1;
unsigned bit4: 1;
unsigned bit5: 1;
unsigned bit6: 1;
unsigned bit7: 1;
116 Introduction to the C Language

unsigned bit8: 1;
unsigned bit9: 1;
unsigned bit10: 1;
unsigned bit11: 1;
unsigned bit12: 1;
unsigned bit13: 1;
unsigned bit14: 1;
unsigned bit15: 1;
};

struct BYTES {
unsigned byte0: 8;
unsigned byte1: 8;
};

union WORD {
int x;
struct BYTES byte;
struct BITS bit;
] data;

Now, through the data we can access the complete word (data.x), to one of the two.
bytes (data.byte.byteN), or to individual bits (data.bit.bitN).

We are going to use the function from the standard library equip() in a program that does
use of this capability. The funcónbiosequip() function returns a word with the following information:

bits 14-15 Number of parallel printers


bit 13 Installed printing series
bit 12 Joystick installed
bits 9-11 Number of COM ports
bit 8 Chip DMA installed (0: YES, 1: NO)
bits 6-7 Number of disk drives (sibit0 = 1)
1 disk drive
01: 2 floppy disk drives
10: 3 disk drives
11: 4 disk drives
bits 4-5 Initial video mode
00: Not used
01: 40x25 BN, color adapter
10: 80x25 BN, color adapter
11: 80x25 BN, monochronic adapter
bits 2-3 RAM on motherboard
00: 16k
32k
10: 48k
11: 64k
bit 1 Mathematical coprocessor 80x87 installed
bit 0 Boot from floppy disk
The following program displays on the screen the information provided by biosequip().

#include <stdio.h>
#include <conio.h>
#include <bios.h>

struct BIOSEQUIP {
1. Introduction 117

unsigned start: 1;
unsigned cop80x87: 1;
unsigned RAM_base: 2;
unsigned video: 2;
unsigned discs: 2;
unsigned DMA: 1;
unsigned ports: 3;
unsigned games: 1;
unsigned series: 1;
unsigned parallel: 2;
};

union TEAM {
int word;
struct BIOSEQUIP bits;
};

void Present (void);

void main (void)


{
union TEAM bios;

bioequipment();

clear screen ();


Present();

gotoxy (31, 1);


if (bios.bits.cop80x87) puts ("SI");
else puts ("NO");

gotoxy (31, 2);


printf ("%d Kb", (bios.bits.RAM_base + 1) * 16);

gotoxy (31, 3);


switch (bios.bits.video) {
case 1: 40x25 Black and White, Color Adapter
break;
case 2: 80x25 Black and White, Color Adapter
break;
case 3: 80x25 Black and White, Monochrome Adapter
}

gotoxy (31, 4);


if (bios.bits.boot) printf("%d", bios.bits.drives + 1);
else puts ("0");

gotoxy (31, 5);


if (bios.bits.DMA) puts ("NO");
else puts ("YES");

gotoxy (31, 6);


printf("%d", bios.bits.ports);

gotoxy (31, 7);


if (bios.bits.games) puts("YES");
Introduction to the C Language

else puts ("NO");

gotoxy (31, 8);


printf ("%d", bios.bits.serie);

gotoxy (31, 9);


printf("%d\n", bios.bits.parallel);
}

void Present (void)


{
Mathematical Coprocessor .....
RAM on the motherboard ...........
Initial video mode .......
Number of diskette units .....
Chip DMA ....................
Number of COM ports ...........
puts ("Joystick .................... ");
Serial printer .............
Parallel printers .........
}

Enumerations

They are groups of constants grouped in a manner similar to structures and that allow
control the range of a variable. The syntax that allows you to define an enumeration is:

Invalid input
constant1;
constant2;
...
...
constantN;

being_name_enumerationthe identifier that names the enumeration, andvariablethe


variable that can take the defined values for constant1, constant2, ..., constantN. These
constants take on the values 0, 1, 2, ..., N. For example:

enum COLORS {
BLACK;
BLUE
GREEN
CYAN
RED
PURPLE
YELLOW
WHITE;
}

For an enumeration like the above, the statement

printf("%d %d", BLUE, PURPLE);


1. Introduction 119

it would display the values 1 and 5 on the screen. Statements of the type are also possible

switch (color) {
case BLACK: ...
break;
case BLUE: ...
...
...
...
}

It is important not to forget that the values defined with the identifiers BLACK,
AZUL, etcetera, are not variables but constants.

It is possible to modify the range of values of an enumeration by initializing the constants.


at the time of the declaration. Thus, the enumeration

enum VALUES {
CTE1;
CTE2;
CTE3 = 25;
CTE4;
CTE5 = 31;
};

define the constants of the enumeration with the following values

0
CTE2: 1
25
CTE4: 26
CTE5: 31
120 Introduction to the C Language

Exercises
1. We wish to create a price list of the items from the company QUIEBRA, S.A. The
data to process for each item are as follows:

Article code: 3-character string.


Description: Chain of 40 characters.
Components: Matrix of 5 elements. Each element of this matrix will contain the
next fields:
Component code: String of 8 characters.
Integer between 1 and 100.
3. Unit price: Whole number between 500 and 5000.

Build a program that performs the following tasks:

a) Capture the item data from the keyboard, storing it in an array.


(maximum, 25 items).
b) Print the matrix data in the following format:

QUIEBRA, S.A. Price list Page:XXX

COMPONENTS
Code Code Can't Price Amount
xxx xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxx xxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
Total xxxxxxx

xxx xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxx xxxxxx xxxxxxx


xxxxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
xxxxxxxx xxxxx xxxxxx xxxxxxx
Total xxxxxxx

... ... ... ... ... ...


... ... ... ... ... ...
... ... ... ... ... ...
... ... ... ... ... ...

Print 5 items per page.

2. Function #2 of INT 17h returns the status of a specified parallel port with the
DX record. The prerequisites for the function are:

AH = 2
Number of the parallel port
0 - LPT1:
1 - LPT2:
1. Introduction 121

...
...

The function returns the status of the port in AH. The bits of AH should be interpreted as
continue:

bit 0 The printer did not respond in the expected time.


bits 1-2 Not used
bit3 I/O error
bit4 Selected printer
bit5 Without paper
bit6 Printer acknowledgment (Acknowledgment receipt ACK)
bit7 Free printer

Build a program that displays this information for the first parallel port
(LPT1:)

9
Dynamic assignment
by heart

Static and dynamic storage


The conventional way of storing variables in memory is called
static storage: at the beginning of the program, variables are declared and space is reserved
amount of memory needed. This is the system we have used so far in all
the exercises and examples. With this method, when a program uses an array, previously
we decide the maximum size that is needed and declare the array according to that size
maximum. For example, if the program uses a two-dimensional array of integers and we assume that
the maximum number of rows and columns you will need is 100x100, we will make a declaration like

int matrix[100][100];

with which we will be reserving 100 x 100 x 2 = 20000 bytes of memory at the start of the program
(assuming they are available) and will remain reserved throughout the program,
regardless of whether they are used to store values or not.

This type of storage has some drawbacks. Let's take a look at Exercise 3 of
Chapter 7 (page 118) in which a magic square is constructed. In that program, work is done
with a matrix whose dimension can range from 3x3 to 19x19. For the square of dimension
a minimum of 18 bytes of memory is needed; when using the maximum dimension, it is necessary
722 bytes. But, regardless of the magic square that is to be built, we must
declare the matrix of the maximum size, and when the square of lower orders is constructed
Introduction to the C Language

19 we will be wasting a certain amount of memory. In this program, this is not too much.
important, but it is for others who use larger matrices. If the referred exercise were to deal with
very large order squares, the amount of wasted memory could be very
important. Just look at the fact that a matrix of integers of order 500x500 needs,
approximately 0.5 Mb of static storage.

The ideal alternative would be for the program to request the system for the amount of
precise memory in each case. For the magic square, it would mean asking the system for 18 bytes.
for the order 3x3 and 722 bytes when building the square of order 19x19. This is achieved
with dynamic memory allocation, through which the program requests the system
the memory that is needed and returning the one that is no longer necessary. For this purpose, the
malloc() and free() functions, which we will study in the next section.

Dynamically allocated memory is taken from a region called the heap.


its size is variable, depending on the memory model9used to compile the program.

Basically, the way to place data and code of a program in memory addresses the
next scheme:

High directions PILOT


(Local data)

MOUND
(Dynamic data)

Global data

CODE
Low directions

The size for the code and global data zones remains constant during
the whole program. The stack grows downward and local scope variables are stored in it
used by the functions. The heap, also referred to as the free storage area,
grows upward, as memory is dynamically allocated at the request of the program. In
In some cases, the stack may overlap part of the heap. It may also happen that the heap does not
can meet all the program's memory demands. These problems can
control yourself with C's dynamic allocation functions.

The functions malloc() and free()

They are the two basic functions for dynamic memory allocation. With the function
malloc() requests memory from the heap. The free() function returns memory to the heap.
The prototype for the function malloc() is

void *malloc (size_t size);

9
The memory models are studied in Chapter 12.
1. Introduction 123

and is defined in stdlib.hyalloc.h. This function allocates a block of tamabytes from the heap. If
the requested amount of memory is available, malloc() returns a pointer to the area of
assigned memory. Otherwise, it returns a null pointer. The type void * indicated in the
prototype means that the pointer returned by malloc() can (and must) be transformed to
any kind. The following example requests memory for 100 integer data:

int *block;
...
...
block = malloc(200);
if (!block) {
Insufficient memory
Function_error ();
}

If the malloc() function is successful, the pointer will have the address of an area of
200 bytes from the heap. Otherwise, we must terminate the program or execute a routine to
Error. Special care must be taken not to work with null pointers, as this causes,
generally, the system crash.

Although the previous example is correct, it is recommended to make the amalloc() call from the
following form:

int *block;
...
...
block = (int *) malloc (100 * sizeof (int));
if (!block) {
Insufficient memory
Function_error ();
}

it ensures the portability of the code.

The free() function has the following prototype

void free (void *block);

and requires the inclusion of the header file alloc.h. This function returns the block to the heap.
memory pointed by block, being block a pointer provided by a call
previous amalloc(). The memory returned by free() can be reassigned by another call to
malloc()

The program on the next page illustrates the use of both functions. It requests
memory to store a variable-length string. Memory will only be used
necessary given by the length of the string.
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <stdlib.h>
#include <process.h>

void main (void)


{
char *string;
int N;

clearscreen();
Introduction to the C Language

EXAMPLE OF DYNAMIC MEMORY ALLOCATION


String length:
scanf ("%d", &N);
getchar();
Remove the Intro from the entry

string = (char *) malloc (N + 1); //N + 1 to include the final null


if (!string) {
INSUFFICIENT MEMORY
exit (1); }
Assigned address: %p

Enter %d characters:
gets (string);
You have typed: %s

free (chain);
}

Other dynamic allocation functions of Turbo C are: allocmem(), calloc(), coreleft(),


farcalloc(), farmalloc() realloc().

Dynamically assigned matrices


The aforementioned magic square program illustrates quite well one of
the situations where it is convenient to use dynamic programming: the program handles a
matrix whose size cannot be determined a priori.

The following program solves the magic square exercise using assignment.
memory dynamic. Although in this case it is not necessary, the order limitation is maintained.
maximum size of 19x19, for display purposes. Moreover, it is assumed that the functions
Intro() and Strdigit() are found in separate object modules that will be linked.
later10.

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <alloc.h>
#include <process.h>

void main (void)


{
int *magico, *p;
int i, j, ant_i, ant_j, order, top;
register int value;
char N[3];

10
The independent compilation and linking of the integrated programming environment
They are studied in Chapter 12 of Turbo C.
1. Introduction 125

clear screen();
MAGICAL SQUARE OF ODD ORDER N (3 to 19)
do {
do {
Value of N:
Intro (wherey (), wherex (), 2, N);
} while (!Strdigit (N));
order = atoi(N);
} while (order < 3 || order > 19 || !(order % 2));
top = order * order;

magico = (int *) malloc (top * sizeof (int));


if (!magico) {
Insufficient memory
exit (1);
}

for (i = 0; i < order; i++) {


for (j = 0; j < order; j++) {
p = magic + i * order + j; Address of
magical[i][j]
*p = 0;
}
}

i = 0;
j = order / 2;
for (value = 1; value <= limit; value++) {
p = magical + i * order + j; //Address of
magico[i][j]
if (*p) {
i = ant_i + 1;
j = ant_j;
if (i > order - 1) i = 0;
}
p = magic + i * order + j; //Address of
magical[i][j]
*p = value;

ant_i = i--;
ant_j = j++;
if (i < 0) i = order - 1;
if (j > order - 1) j = 0;
}

clrscr ();
for (i = 0; i < order; i++) {
for (j = 0; j < order; j++) {
p = magic + i * order + j; //Address of
magic[i][j]
printf ("%3d ", *p);
}

}
free (magical);
}
126 Introduction to the C Language

Dynamic queues
A queue is a FIFO (First In, First Out) structure, meaning the first element that
enters the structure is the first to exit. The queues fit very well to the type of structures
susceptible to being programmed dynamically, as they are structures that grow and contract to
as information comes in and out of them.

To dynamically program this type of structures (such as stacks, trees


binaries, etc.) it is necessary to resort to self-referential structures. A structure
self-referential is basically defined as follows:

structstruct_name{
field_of_information1
information_field2
...
...
information_fieldN;
struct structure_name link1;
struct name_structure link2;
...
...
struct structure_name linkN;
};

that is to say, there is one or more fields in which the desired information is stored, and one or
several link fields with other elements. In the case of a dynamic queue of numbers
Integers, each element must link to the next one through a self-referential structure.
like the following:

struct COLA {
int data;
struct COLA *link;
};

being the integer number that is stored in the queue, and linking a pointer to the structure of the
next element of the queue.

The following program manages a dynamic queue of positive integers.


the program's operation is based on a menu of options and on two functions, Introducir() and
Sacar(), which controls the input/output of data in the queue.

The function Introducir() performs the following operations:

Call amalloc() to request memory for the new element. In case it does not
if there is available memory, the function returns a value of 0.
Store the data in the assigned address using malloc().
Traverse the entire queue from the beginning to locate the last element, starting from
which should be included in the new one.
Link the element that was previously the last with the new element introduced in the
cola.
Returns a value of 1.
1. Introduction 127

The function Remove() performs the following operations:

Check if the queue is empty, in which case return a value of -1.


Retrieves the information from the first element of the queue.
Make the second element of the queue the first, pointing it with the pointer of the
element that is taken out.
Return to the heap using free() the memory occupied by the removed element.
Return the extracted value.

The complete program is shown below:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>

struct COLA {
int data;
struct COLA *link;
};

int Menu (void);


int Introduce(int n);
int Withdraw (void);

struct COLA *first;

void main (void)


{
int value, option, st;
first = 0;
while ((option = Menu ()) != 3) {
switch (option) {
Value to enter in the queue:
scanf("%d", &value);
if (!Introduce(value)) {
Out of memory. Press a key ...
while (!getch ());
}
break;
case 2: value = Withdraw();
if (value < 0) puts (" Empty queue");
Obtained value: %d
Press a key ...
while (!getch ());
}
}
}

int Menu (void)


{
int n;

clrscr ();
DYNAMIC COCKTAIL
1. Enter
Introduction to the C Language

2. Take out
3. Exit

do {
n = getch ();
} while (n < '1' || n > '3');

return n - 48;
}

int Introduce (int n)


{
struct COLA *new, *current, *previous;

new = (struct QUEUE *) malloc (sizeof (struct QUEUE));


if (!new) return 0;

new
link = 0;

if (!first) first = new;


else {
actual = first;
while (actual) {
previous = current;
previous
}
previous
}

return 1;
}
int Withdraw (void)
{
struct COLA *first_previous;
int n;

if (!first) return -1;


else {
first
n = first -> data;
first -> link
free (antfirst);
return n;
}
}

Exercises
1. Build a program that manages a stack of integers with dynamic allocation.
memory. The program will present a menu with the options

1. Introduce
1. Introduction 129

2. Take out
3. Exit

The program will have functions Introduce() and Withdraw() similar to those used in the
dynamic queues section of the chapter.

10! Error! Marker not


defined.
Files

Channels and files


It has already been stated that all I/O in C is done through library functions. This, which has already been
studied for I/O through the console, will be studied in this chapter for I/O on any device, in
particular about disk files.

The ANSI C I/O system provides an intermediary between the programmer and the
device that is accessed. This intermediary is called flow channel and is an independent buffer of the
device to which it connects. The real device is called file. Therefore, program and
the files are connected through a channel and the same function allows writing on screen,
printer, file, or any port. There are two types of channels:

Text channels: They are sequences of characters. Depending on the environment, there may be
character conversions (LF CR + LF). This causes the number of characters
written/read in a channel may not match the number of characters written/read in
the device.
Binary channels: They are sequences of bytes. Unlike text channels, in the
binary channels the correspondence of characters in the channel and in the device is 1 to 1, it is
say, there are no conversions.

Afile is, therefore, a logical concept that can be associated with anything that is susceptible to
perform I/O operations with it. To access a file, it must be associated with a channel by
through an opening operation that is carried out by means of a library function. Subsequently
read/write operations can be performed using memory buffers. For these
operations there is a wide range of functions available. To disassociate a channel from a file is
It is necessary to perform a closing operation. There are 5 channels that open whenever a begins.
C program. They are:

standard input Standard input channel. Default is the keyboard. (ANSI)


Standard output stream. By default, the screen. (ANSI)
Standard error output stream. By default, the screen. (ANSI)
Auxiliary channel (serial channel COM1). (From Turbo C v2.0)
130 Introduction to the C Language

StdprnPrint channel for the printer. (Starting from Turbo C v2.0)

Open and close files


To be able to handle a file, it is necessary to associate it with a channel. This is achieved through a
opening operation performed using the library function fopen(), which returns a pointer
the channel that is associated. The prototype of this function is defined in stdio.hy as follows:

FILE *fopen (const char *name, const char *mode);

This function opens the filename and associates it with a channel using the aFILE pointer.
returns. The data type FILE is also defined in stdio.h and is a structure that contains
information about the file. It consists of the following fields:

typedef struct {
short level; occupancy level of
buffer
unsigned flags; control indicators
char fd; //descriptor of
file (number that identifies it)
char hold; character of ungetc()11
short bsize; buffer size
unsigned char *buffer; //pointer to the buffer
unsigned char *curp; current position
short token; it is used for control
} FILE;

None of the fields in this structure should be touched unless you are a programmer.
very expert. Any uncontrolled change in the values of those variables could possibly damage the
file. If any error occurs in opening the file, fopen() returns a null pointer and the
file is left without an associated channel.

The possible values of the parameter mode are shown in the following table:

MODE DESCRIPTION
r Open a file for reading only. If the file does not exist, fopen() returns
a null pointer and an error is generated.
w Create a new file for writing. If a file with this already exists
name, it is overwritten, losing the previous content.
a Open or create a file to add. If the file exists, it opens.
pointingtotheendofit.Ifitdoesnotexist,anewoneiscreated.
r+ Open a file for reading and writing. If the file does not exist fopen()
it returns a null pointer and an error is generated. If it exists, they can
perform read and write operations on it.
w+ Create a new file for reading and writing. If a file with this already exists
name, it is overwritten, losing the previous content. On the
Files can be read and written.
a+ Open or create a file to read and add. If the file already exists, it is opened.
pointing to the end of it. If it does not exist, a new file is created.
To indicate whether the channel associated with the file is text or binary, the letter b is added to the mode.
respectively. Thus, simodoesrt, the file is being opened in text mode only for reading,

11
This function has the prototype ungetc (int character, FILE *stream); and returns the character to the input stream.
which allows it to be read again.
1. Introduction 131

while simodoesw+bse will open or create a file in binary mode for reading and for
writing12.

To close a file and free the previously associated channel confopen(), the following must be used
fclose() function defined in stdio.h whose prototype is

int fclose (FILE *stream);

This function returns 0 if the closing operation was successful, and EOF in case of error. EOF
it is a macro defined in stdio.h in the following way:

#define EOF (-1)

The following program opens a file named DATOS.DAT in read-only mode and,
later closes it.

#include <stdio.h>
#include <process.h> for exit()

void main (void)


{
FILE *f;
int st;

f = fopen("DATOS.DAT", "rt");
if (!f) {
Error opening the file
exit (1);
}

Here would come the operations on the file


st = fclose(f);
if (st) puts("Error closing the file");
}

It is common to write the file opening statement as follows:

if (!(f = fopen("DATOS.DAT", "rt"))) {


Error opening the file
exit (1);
}

Error and end-of-file control

12
When none of the modes are indicated, the opening mode is governed by the global_fmode variable. If it is
initialized with the value O_BINARY, the files are opened in binary mode. If it is initialized as O_TEXT, they are opened in mode
These constants are defined in enfcntl.h.
132 Introduction to the C Language

Every time a read or write operation is performed on a file, we must


check if an error has occurred. For this we have the function ferror() whose prototype,
defined in stdio.h, is

int ferror (FILE *stream);

This function returns 0 if the last operation on the file was successful. There are
to take into account that all operations on the file affect the error condition, so
error control must be performed immediately after each operation, otherwise the
error condition may be lost. The way to invoke this function may be

if (ferror (f)) puts ("File access error");

being a pointer to FILE.

You can obtain a message associated with the last error produced using the perror() function.
whose prototype, defined in stdio.h, is

void perror (const char *string);

This function sends the indicated string in the argument to stderr (usually the screen), two
points and, below, a message from the system associated with the last error produced. The way in which
the error is related to the message through a predefined global variable called errno
defined in errno.h) that is triggered when errors occur. For example, given the segment of
program

FILE *f;

if (!(f = fopen("DATOS.DAT", "rb"))) {


Error %d.
perror("DATA.DAT");
exit (1);
}

if the DATOS.DAT file does not exist, the message is sent to the screen

Error 2. DATOS.DAT: No such file or directory

Every time a read operation is performed on a file, the position indicator of the
The file is being updated. It is necessary, therefore, to control the end-of-file condition. For this reason, we must know
that when attempts are made to read beyond the end of the file, the character read is always EOF.
However, in binary channels, a data can have the value EOF without being the end mark.
file. It is advisable, therefore, to check the end-of-file condition using the feof() function,
whose prototype, defined in stdio.h, is

int feof (FILE *stream);

This function returns a value different from zero when the end of the file is detected.

An algorithm that reads an entire file can be as follows:

#include <stdio.h>
#include <process.h>

void main (void)


1. Introduction 133

{
FILE *f;

if (!(f = fopen("DATOS.DAT", "rt"))) {


DATOS.DAT
exit (1);
}

read operation on DATA.DAT


while (!feof (f)) {
treatment
//read operation on DATA.DAT
}

close (f);
if (ferror(f)) puts("Error closing the file DATOS.DAT");
}

Character I/O

To read individual characters from a file, the function is used

int fgetc (FILE *stream);

or its equivalent macro

int getc (FILE *stream);

Both are defined in stdio.h and are completely identical. They return the read character and
they increase the file position counter by 1 byte. If the end of file condition is detected,
EOF is returned, but for binary streams it is better to check this condition using feof().

To write individual characters to a file, the function is used

int fputc (int character, FILE *stream);


or its equivalent macro

int putc(int character, FILE *stream);

Both have the defined prototype in stdio.hy and are completely identical. They write the
character indicated in the argument (which can also be a variable char) in the associated file
channel. If there is no error, they return the written character; otherwise, they return EOF.

The following program copies character by character the file DATOS.DAT into COPIA.DAT.

#include <stdio.h>
#include <process.h>

void main (void)


{
FILE *fent, *fsal;
char character;
134 Introduction to the C Language

if (!(fent = fopen("DATOS.DAT", "rb"))) {


perror("DATOS.DAT");
exit (1);
}
if (!(fsal = fopen("COPIA.DAT", "wb"))) {
perror ("COPY.DAT");
exit (1);
}

character = getc(fent);
while (!feof (fent)) {
putc (character, fsal);
if (ferror (fsal)) puts ("The character has not been written");
character = getc (fent);
}

fclose (fent);
fclose (fsal);
}

The same operation can be performed in a single line by

while (!feof (fent)) putc (getc (fent), fsal);

There are two functions analogous to agetc() and putc() but for reading and writing integers instead of
characters:

int getw (FILE *stream);

int putw (integer, FILE *stream);

Both are defined in stdio.h and the only difference with getc() and putc() is that they
two bytes are processed in each operation. These two bytes must be interpreted as an integer. The
The function getw() should not be used with files opened in text mode.

Input/Output of strings

To read character strings, the function is used

char *fgets (char *string, int n, FILE *stream);

whose prototype is defined in stdio.h. This function reads characters from the file associated with acanaly.
store chain. In each read operation, n - 1 characters are read, unless found
first a newline character (which is also stored chained). If no error occurs, the
function returns a pointer to a string; otherwise, it returns a null pointer.

The following program displays the contents of the AUTOEXEC.BAT file, numbering the
lines. It is assumed that no line has more than 80 characters.

#include <stdio.h>
1. Introduction 135

#include <process.h>

void main (void)


{
FILE *f;
register int i = 1;
char string[81];

if (!(f = fopen("AUTOEXEC.BAT", "rt"))) {


perror ("AUTOEXEC.BAT");
exit (1);
}
fgets (string, 80, f);
while (!feof (f)) {
%d: %s
i++;
fgets (string, 80, f);
}
fclose (f);
}

To write strings, the function is used

int fputs (const char *string, FILE *stream);

whose prototype is defined in stdio.h, and that writes the indicated string in the file
associated channel. It should be noted that fputs() does not copy the null character nor adds a character.
new line at the end. If no error occurs, fputs() returns the last character written; otherwise
returnsEOF.

The following program prints the character strings that are being typed.
until pressed .

#include <stdio.h>
#include <string.h>

void main (void)


{
char *string[85];

Enter string:
gets (string);
while (string[0]) {
strcat (string, "\n\r");
fputs (string, stdprn);
gets (string);
}
}

Data block I/O


136 Introduction to the C Language

The C standard library provides functions that allow reading and writing blocks of data.
of any kind. The functions that perform these operations are, respectively, fread() and
fwrite(), whose prototypes, defined in stdio.h, are as follows:

int fread (void *buffer, int nbytes, int contador, FILE *canal);

int fwrite (void *buffer, int nbytes, int contador, FILE *stream);

The fread() function reads a count of data blocks from the associated file and places them in
buffer. Each block contains bytes. The fwrite() function dumps into the associated file.
block counter of bytes that are stored from the buffer. If the operation
it is successful, fread() returns the number of blocks (not bytes) actually read. Similarly,
fwrite() returns the actual number of blocks written. The statement

void *buffer

indicates that it buffers a pointer to any type of variables.

In the following program, a set of 10 numbers is stored in the file MATRIZ.FLO


of tipofloat. Writing is done with a fwrite() statement for each data. In the reading operation
the 10 data is read all at once with a fread() statement and then displayed in
screen.

#include <stdio.h>
#include <process.h>
#include <conio.h>

void main (void)


{
register int i;
FILE *f;
float elem, matrix[10];

if (!(f = fopen("MATRIZ.FLO", "w+b"))) {


perror("MATRIX.FLO");
exit (1);
}

for (i = 0; i <= 9; i++) {


Enter number:
scanf("%f", &elem);
fwrite(&elem, sizeof(elem), 1, f);
}
rewind (f);

fread(matrix, sizeof(matrix), 1, f);

clrscr ();
for (i = 0; i <= 9; i++) printf ("\n%d: %f", i, matrix[i]);

fclose (f);
}

Let's take a look at some details of the previous program. The statement
1. Introduction 137

fwrite(&elem, sizeof(elem), 1, f);

dump into the file, each time, the 4 bytes -sizeof (elem)- of elem. Once the first of the
for loops have executed 10 fwrite() operations, and therefore, the file position indicator
point to the end of it. In order to read the data, we need to reposition this indicator.
at the beginning of the file. This can be done in two ways:

Closing the file and reopening it for reading.


Using the rewind() function.

In the example, the second method is used. The function rewind() repositions the pointer of
position of the file at the beginning of it. Its prototype, defined in stdio.h, is as follows:
void rewind (FILE *stream);

Continuing with the previous program, the statement

fread(matrix, sizeof(matrix), 1, f);

Read 40 bytes from the file -sizeof (matrix)- and place them in the matrix. Let's note that it is no longer necessary
write &matrix in the first parameter, because matrix is a pointer.

Typically, fread() and fwrite() are used to read or write structures. Let's see it with a
program that creates a phone directory file. The record of that file will consist of the following
fields:

Name 40 characters
Address 40 characters
Population 25 characters
Province 15 characters
Phone 10 characters

The following program creates that file, called LISTIN.TEL.

#include <stdio.h>
#include <conio.h>
#include <process.h>

typedef struct {
char name[41];
char dom[41];
char pob[26];
char pro[16];
char tel[11];
REG;

void main (void)


{
FILE *f;
REG var;

if (!(f = fopen("LISTIN.TEL", "wb"))) {


perror("LISTIN.TEL");
exit (1);
}
138 Introduction to the C Language

clear screen ();


printf("Name: ");
gets (var.name);
while (var.nom[0]) {
Address:
gets (var.dom);
Population:
gets (var.pob);
Province:
gets (var.pro);
Telephone:
gets (var.tel);

fwrite(&var, sizeof(var), 1, f);


if (ferror (f)) {
The information has not been stored.
getch();
}

clear screen();
printf("Name: ");
gets (var.nom);
}

fclose (f);
}

The following program illustrates how to read blocks of records from a file.
Specifically, read the records from the file LISTIN.TEL in groups of 4, displaying on the screen the
fieldsNameandPhone.

#include <stdio.h>
#include <conio.h>
#include <process.h>

typedef struct {
char name[41];
char dom[41];
char pob[26];
char pro[16];
char tel[11];

void main (void)


{
FILE *f;
REG var[4];
int i, n;

if (!(f = fopen("LISTIN.TEL", "rb"))) {


perror("LISTIN.TEL");
exit (1);
}

do {
1. Introduction 139

clrscr();
n = fread(var, sizeof(REG), 4, f);
for (i = 0; i < n; i++) printf ("\n%-41s %s", var[i].nom, var[i].tel);
Press a key ...
getch();
} while (!feof (f));

fclose (f);
}
If we look at the fread() statement of this program, 4 blocks are read in each operation.
sizeof (REG)bytes (135, size of each record). The same amount of bytes would be read by the
sentence

fread (var, sizeof (var), 1, f);

however, we would not have adequate control over the variable.

Input/Output with format

The function that allows you to write with formatting in a file is

int fprintf (FILE *stream, const char *format, argument list);

that writes the arguments of the list, in the indicated format, in the associated file channel. This
The function is identical to printf() except that it allows writing to any device and not just to stdout.
A use of defprintf() was studied in Chapter 4 for printer output.

To read with format, there is the function

int fscanf (FILE *stream, const char *format, list of arguments);

What is identical to ascanf() except it can read from any device, not necessarily destdin.

Although these functions can be very useful in certain applications, in general it is more
it is advisable to use fread() and fwrite().

Direct access

Direct access (both for reading and writing) to a file is carried out with the help of the
function fseek() that allows positioning the file's pointer anywhere within it. The
the prototype of this function is:

int fseek (FILE *stream, long nbytes, int origin);

This function sets the file pointer indicator bytes counted from origin. The
Possible values of the origin parameter and its associated macros are shown in the following table:
140 Introduction to the C Language

Error! Marker not VALUE MACRO


defined.ORIGIN

Beginning of the file 0 SEEK_SET


Current position 1 SEEK_CUR
End of file 2 SEEK_END

The function returns 0 when it has succeeded. Otherwise, it returns a different value.
0.

This function simply handles the file position indicator, but does not perform any
read or write operation. Therefore, after using fseek(), a read function must be executed.
or writing.

The following program creates a file called FRASE.TXT with a string of characters.
Later, read a character from the string at the position you type.

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <process.h>

void main (void)


{
FILE *f;
int nbyte, st;
char phrase[80], character;

if (!(f = fopen("FRASE.TXT", "w+t"))) {


perror("FRASE.TXT");
exit (1);
}

clear screen();
Type phrase:
gets (phrase);
fwrite(frase, strlen(frase) + 1, 1, f);

Read character no:


scanf ("%d", &nbyte);
st = fseek(f, (long)nbyte, SEEK_SET);
if (st) puts("Positioning error");
else {
character = getc(f);
if (character != EOF) printf ("\nThe character is: %c", character);
else puts("End of file exceeded");
}

fclose (f);
}
1. Introduction 141

fseek() can be used to access records. To do this, it is necessary to first calculate which byte.
The file begins the sought record. The following program writes records by using
fseek().

#include <stdio.h>
#include <conio.h>
#include <process.h>

typedef struct {
char name[40];
int age;
float height;
REGISTRATION;

void main (void)


{
FILE *f1;
REGISTER mireg;
int num;
long int pointer;

if (!(f1 = fopen("REGISTRO.DAT", "r+b"))) {


Error opening
exit (1);
}

clear screen();
printf("Write record number: ");
scanf ("%d", &num);
while (num > 0) {
getchar();
printf("Name: ");
gets (mireg.name);
Age:
scanf("%d", &mireg.edad);
Height:
scanf ("%f", &mireg.height);
pointer = (num - 1) * sizeof (RECORD);
if (fseek (f1, pointer, SEEK_SET)) puts ("Positioning error");
else {
fwrite (&mireg, sizeof (mireg), 1, f1);
if (ferror(f1)) {
WRITE error
getch();
}
}
clearscreen();
Print record number:
scanf("%d", &num);
}

fclose (f1);
}
142 Introduction to the C Language

Exercises
1. Write a program that stores all the characters in a file that are
Type until CTRL-Z is pressed. The name of the file will be passed as a parameter in the
line of orders.

2. Write a program that reads a text file and changes all occurrences of a
a word determined by another. The program will run with the command

PROG file word1 word2

word1 the word replaced by word2. The program must inform of


number of substitutions made.
Note: It will be assumed that the lines of the file do not have more than 80 characters.

3. At the BAHEETO'S BASKET CLUB basketball club, a


campaign to recruit tall players. There is a file with data of applicants,
called ALTOS.DAT, which is described below

ALTOS.DAT Aspiring players of the club


Field Description Type
name Name of the applicant )
alt Height of the applicant (in meters) float
pro Province of birth
Char type fields include the final null.
The file stores a maximum of 500 records.
The province is stored in uppercase.
The file is not sorted.

Build a program that performs the following operations:

Request a province via keyboard and store the names and the
heights of the applicants born in the indicated province.
Calculate the average height of all the applicants from that province.
Issue a printed report with the names and heights of the candidates from the province
whose height exceeds the average. The format of the list must be as follows:

Province: xxxxxxxxxxxxxxxxxxxxxxxxx
Height Media: x.xx

Name
Height
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x.xx
... 50 lines of detail per page
4. There are two data files ARTIC.DAT and NOMPRO.DAT, which are described at
continuation:

ARTIC.DAT Master of Articles


Field Description Type
cod Article code char(7)
of the Description char(31)
exit Existence unsigned
1. Introduction 143

pco Purchase price unsigned


pvp Selling Price unsigned
pro Supplier code char(5)
Char type fields include the final null
The fields only store numeric digits and are completed to the
left padded with zeros. For example, the item with code 65 is stored as 000065.
The file is sorted in ascending order by the campocod.
Not all values are decoded.

NOMPRO.DAT Supplier names


Field Description Type
name Supplier name )
Each supplier name is stored in the record whose number matches
his code. Thus, the name of the provider with code 000041 is stored in the record.
41.

Write a program that generates a printed report in the format of the following page.
At the beginning of the program, the initial and final item codes will be requested via keyboard.
they will limit the records that need to be listed.
Introduction to the C Language

You might also like