C Language With Resolved Exercises
C Language With Resolved Exercises
1
Introduction
Brief history
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.
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.
#include <stdio.h>
main ()
{
int dozen;
docena = 12;
A dozen is %d units
}
#include <stdio.h>
main ()
int dozen;
dozen = 12;
A dozen is %d units
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).
Example 2: scanf()
The following program performs the conversion from feet to meters using the
equivalence
The program asks for the number of feet via keyboard and displays on screen the
corresponding metros.
6 Introduction to the C Language
#include <stdio.h>
main ()
{
int pies;
float meters;
Feet?:
scanf("%d", &pies);
float meters;
Feet?:
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
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
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.
#include <stdio.h>
main()
{
This message is displayed by the main() function
MyFunction();
}
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.
#include <stdio.h>
main ()
{
int num;
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()
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.
... 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).
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.
#include <stdio.h>
main ()
{
int a, b, product;
The result is %d
}
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);
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.
Exercises
include studio.h
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:
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
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.
Integer constants are considered positive unless preceded by the minus sign.
(-):
Real Constants
They are also called floating-point constants. They have the following format:
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
Character constants
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.
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
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:
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.
Selling Price
Num1
_123
D_i_5
Theyarenotvalid:
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,
These comments can be nested in Turbo C++, although it is not advisable to allow the
code compatibility.
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:
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.
Arithmetic operators
OPERATOR DESCRIPTION
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.
x++ x- -;
x = x + 1; x = x - 1;
1. Introduction 17
++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.
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
== 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
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:
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
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 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.
F F F
F V V
V F V
V V F
a 0xA1B2
b 0x1234
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
a = b shifted left by 4;
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
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);
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);
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
the variable takes the value 100 when x > 9, and 200 otherwise.
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
dir_a = &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;
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 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.
(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;
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.
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.
1st ( ) [ ] . ->
24 Introduction to the C Language
4th + -
8th &
9th ^
10th |
11th &&
12º ||
13th ?:
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].
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.
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.
#include "file_name"
or well,
#include <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:
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>
#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
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
Input/output error
MESSAGE
that displays the string of characters MESSAGE on screen. Statements can also be written
as
#define A 1
#define B 2
#define TRES A + B
Exercises
1. Representa de 3 maneras diferentes el carácter nueva línea.
1. Introduction 27
3. Indicate which of the following identifiers are not correct and why.
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?
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:
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.
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.
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.
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.
The storage classes and type modifiers will be studied in the following sections.
of the chapter.
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
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.
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.
b) The data type char is not affected by the modifiers short or long.
c) Turbo C allows a shorthand notation to declare integers without using the reserved word int.
d) The modified signed and unsigned cause an error if applied to the float types
double.
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
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
Local variables
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.
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
car
external
static
register
...
Function ( ...
{
auto int a; /* Declare the variable as local to Function */
...
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.
ExternalFunction();
}
InternalFunction()
{
printf ("x=%d, y=%d", x, y);
}
x=10, y=20
Since for the three functions - main(), FuncionInterna() and FuncionExterna() - the variables x and y
they are the same.
Static variables
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.
increment()
{
int n;
n++;
n=%d
}
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);
}
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;
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.
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:
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:
void main ()
{
unsigned char character;
scanf("%c",&character);
character> 127 ? character++ : character--;
printf("%c", character);
}
int a;
void main ()
{
int b;
...
}
MyFunction()
{
int c;
static int d;
...
}
1. Introduction 37
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
...
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:
#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
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
whoseeffectisidenticaltothatproducedbythefunctiongetche().
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.
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.
#include <stdio.h>
void main ()
{
charphrase[31];
Type a phrase:
gets (phrase);
You have typed: %s
}
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:
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.
%s stringofcharacters
%% thecharacter%
Pointers %n theyrefertopointersandthemselves
%p theywillstudyinChapter7
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.
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
[1234] visualize[1234]
[%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.
When the number of decimals is greater than n, the last digit is rounded.
Format modifiers can be used to visualize integers short and long, by putting,
respectively, hylants ded, u, o, x, X.
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():
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
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);
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.
stores in, byc, respectively, data entered in any of the following ways:
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
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
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
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
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
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
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.
scanf("%[a-z]s", phrase);
scanf("%[0-9][p-t]s", phrase);
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
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
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
The functions where x() and where y() return the coordinates of the current cursor position:
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
being:
x1, y1: column, row of the upper left corner of the area of the screen to scroll.
1. Introduction 47
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:
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
The function textbackground() sets the background color for all text that is written in
screen below.
background (background_color);
The function textattr() sets the complete attribute byte (character color, background color,
blinking yes/no and high/low intensity). It is written
textattr (attribute);
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:
The allowed values for video_mode and the associated macros are shown in the table.
next.
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
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:
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
Let's look at some examples that illustrate the use of these escape sequences.
printf ("\033[5;20H");
1. Introduction 51
However, for this type of operations, it is more convenient to define a function that
receive the coordinates in the parameters:
ESC [2J
printf ("\033[2J");
produce the same effect as the library function clrscr(). It can be abbreviated in writing
this sequence using a macro like
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
or also
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:
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
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
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:\>
If we write
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
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:
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:
The if structure
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)
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");
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.
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");
}
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.
3 Function3()
4 Function4_1() and Function4_2()
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;
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
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);
}
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
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:
expression1
FALSE
expression2
TRUE
loop_body
expression3
62 Introduction to the C Language
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.
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 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.
void main ()
{
int num;
int n = 0;
while (n != num) {
Type a number between 1 and 20:
scanf("%d", &n);
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.
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
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
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
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);
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.
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
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');
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.
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:
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
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:
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.
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.
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
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);
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;
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.
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.
void main ()
{
int a = 3, b = 4;
aux = x;
x=y;
y = aux;
}
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
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
void main ()
{
int a = 3, b = 4;
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
The parameters x and y are special variables, called pointers, that store addresses.
from memory. In this case, they store addresses of integers.
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:
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
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.
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>
main ()
{
float a, b, total;
we would write
total = multiply(a);
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
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
n! = n · (n - 1)!
0! = 1
We will now represent the recursion process in a diagram when calling, for example, to
factorial(3).
factorial (3)
This process can be compared to that which generates the iterative solution:
{
register int i;
long total = 1;
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
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
Exercises
1. Introduction 79
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
The angle must be a value between 0 and 360. In case, a message will be sent to
screen.
thatIsolvethecalculation.
3. Write a program that shows the first N terms of the Fibonacci sequence.
using a recursive function
thatreturnstheelementN.ThevalueNwillbereadfromthekeyboard.
5. Through the bioskey() function, create a program that displays the status on the screen of
keyboard keystroke in the following format:
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.
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.
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.
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.
that captures a key press and returns the scanning code, and through
return, its ASCII code. Use the bioskey() function.
1. Introduction 81
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.
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.
Memory addresses
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
1393 date
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.
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
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 *m;
...
...
printf ("%p", m);
#include <stdio.h>
#include <conio.h>
clrscr ();
printf("Hello world %n", &p);
%d characters have been written
}
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;
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;
p = x;
since you are a variable of type float (stores a float data), while storing it
direction of a float type data.
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.
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.
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];
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.
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];
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.
Concatenating acad2 to acad1 returning the address of acad1. Remove the null termination of
initialcad1
Example:
One must ensure that the size is adequate to store the result.
Returns the address of the first occurrence of the character in the string. If not
find returns a null pointer.
Example:
Example:
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.
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");
Example:
1. Introduction 89
char cad[30];
...
...
Type a phrase:
gets (cad);
The phrase <<<%s>>> has %d characters
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
Example:
char cad[80];
...
...
Type a phrase:
gets (cad);
Reversed phrase: %s
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);
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
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 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.
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.
clrscr();
Type a string of characters:
1. Introduction 91
gets (string);
int array[100];
We can identify an element, let's say 25, in either of the following two ways:
matrix[24];
*(matrix + 24);
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.
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()?
register int i;
p1 = cad1;
p2 = cad2;
while (*p1) {
if (*p1 - *p2) return (*p1 - *p2);
else {
p1++;
p2++;
}
}
return 0;
}
p1 = cad1;
p2 = cad2;
Two-dimensional matrices
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.
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]);
void main(void)
{
char string[10][70];
register int i, j;
#include <string.h>
clearscreen();
for (i = 0; i <= 9; i++) {
String number %d:
gets (string[i]);
strupr(cadena[i]);
}
(matrix + i * number_of_rows + j)
In C, arrays of more than 2 dimensions can be handled. To declare these arrays, it is done
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.
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:
The provided text is not a translatable sentence. It appears to be a programming code snippet.
Invalid input for translation
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.
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
The following program loads a matrix of integers from the keyboard and displays the largest of them.
calculating it through a function.
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 (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];
function (3Dmatrix);
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.
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:
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
The following program lists the parameters, if any, of the command line.
#include <stdio.h>
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]);
}
}
#include <stdio.h>
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]);
}
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]);
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>
x = 10;
p = &x;
q = &p;
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>
while (( n = menu()) != 3) {
Type two numbers:
1. Introduction 101
clrscr ();
0. Sum
1. Subtract
2. Product
3. Exit
do {
option = getch();
} while (option < '0' || option > '3');
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
1 1 6 8 1 6
3 3 5 3 5 7
2 4 2 4 9 2
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().
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.
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.
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.
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.
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.
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.
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:
dondetipoes a data type and nombrees is the new name for the previous data type. For
example:
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
structname_structure{
type variable1
type variable2;
...
...
type variableN;
};
struct FICHA {
char name[40];
int age;
float height;
};
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
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:
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:
struct FICHA {
char name[40];
int age;
float height;
} var1, var2;
In the previous statements, 4 variables are declared with the FICHA structure: var1 and var2.
global; var3, local main(); and var4, local aFunction().
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.
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:
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:
struct FICHA {
char name[40];
int age;
float height;
};
struct DATE {
int day;
int month;
int year;
};
struct CUMPLE {
char name[40];
struct DATE birth;
};
anniversary.name
birthday.celebration.day
birthday. birth. month
birthday.year
Structure matrices
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]
#include <stdio.h>
#include <conio.h>
struct FICHA {
char name[40];
int age;
float height;
};
void Function(int);
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 *);
clear screen();
Function (&record.age);
}
#include <stdio.h>
#include <conio.h>
struct FICHA {
char name[40];
int age;
float height;
};
clear screen();
Function (record);
}
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
p = &var;
( *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;
};
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.
struct MIESTR {
int i: 2;
unsigned j: 5;
int : 4;
int k: 1;
unsigned m: 4;
};
Introduction to the C Language
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
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.
struct MIESTR {
char a;
int b;
float c;
};
1. Introduction 113
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
mivar.b = 120;
does not affect amivar.ani amivar.c, since each of them has assigned different addresses.
memory.
union MIUNION {
char a;
int b;
float c;
};
This statement allocates 4 bytes of memory for var (the largest field of the union
esc, of 4 bytes).
mivar
3 2 1 0
mivar.b = 120;
Introduction to the C Language
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
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.
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:
#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;
};
bioequipment();
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;
enum COLORS {
BLACK;
BLUE
GREEN
CYAN
RED
PURPLE
YELLOW
WHITE;
}
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.
enum VALUES {
CTE1;
CTE2;
CTE3 = 25;
CTE4;
CTE5 = 31;
};
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:
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
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:
Build a program that displays this information for the first parallel port
(LPT1:)
9
Dynamic assignment
by heart
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.
Basically, the way to place data and code of a program in memory addresses the
next scheme:
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.
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
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 ();
}
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>
clearscreen();
Introduction to the C Language
Enter %d characters:
gets (string);
You have typed: %s
free (chain);
}
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>
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;
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.
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.
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
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>
struct COLA {
int data;
struct COLA *link;
};
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;
}
new
link = 0;
return 1;
}
int Withdraw (void)
{
struct COLA *first_previous;
int 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.
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:
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
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:
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()
f = fopen("DATOS.DAT", "rt");
if (!f) {
Error opening the file
exit (1);
}
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
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
You can obtain a message associated with the last error produced using the perror() function.
whose prototype, defined in stdio.h, is
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 the DATOS.DAT file does not exist, the message is sent to the screen
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
This function returns a value different from zero when the end of the file is detected.
#include <stdio.h>
#include <process.h>
{
FILE *f;
close (f);
if (ferror(f)) puts("Error closing the file DATOS.DAT");
}
Character I/O
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().
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>
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);
}
There are two functions analogous to agetc() and putc() but for reading and writing integers instead of
characters:
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
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>
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>
Enter string:
gets (string);
while (string[0]) {
strcat (string, "\n\r");
fputs (string, stdprn);
gets (string);
}
}
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
#include <stdio.h>
#include <process.h>
#include <conio.h>
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
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:
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);
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
#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;
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];
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
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.
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:
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
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>
clear screen();
Type phrase:
gets (phrase);
fwrite(frase, strlen(frase) + 1, 1, f);
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;
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
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:
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