Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Introducción
Fundamentos
Las variables y los tipos básicos
Introducción
Identificadores, tipos y tamaños
La instrucción LET
Ámbito
Subprogramas y funciones
Introducción
Retorno de valores
Paso de parámetros
Declaración y comprobación de tipos
Ejemplos
Expresiones
Introducción
La asignación
Operadores
Control de flujo
Introducción
La sentencia IF
El bucle WHILE
El bucle DO - WHILE
El bucle FOR
La instrucción EXIT
La selección múltiple SELECT CASE
Arrays (matrices)
Introducción
Declaración
Inicialización
Arrays multidimensionales
Paso de un array a un procedimiento
Manejo de archivos
Lectura de archivos. Operaciones y funciones básicas
Escritura de archivos. Operaciones y funciones básicas
Otras funciones para el manejo de archivos
Estilo de programación
Aspecto del código
Los comentarios
Los nombres de las variables
Fuentes bibliográficas
BASIC básico. Ricardo Aguado, Agustín Blanco, Javier Zabala, Ricardo Zamarreño.
Programación I. UNED. José Cerrada, Manuel Collado.
Curso de programación en C. Miguel A. Garcies. www.uib.es
Curso de C. Gorka Urrutia. www.elrincondelc.com
BASIC es un lenguaje de programación de propósito general que ofrece economía sintáctica, control de flujo, estructuras sencillas
y un buen conjunto de operadores. Es un lenguaje que no está especializado en ningún tipo de aplicación. Esto lo hace un
lenguaje versátil y potente, con un campo de aplicación ilimitado y, sobre todo, se puede aprender rápidamente. En poco tiempo,
un programador puede utilizar la totalidad del lenguaje.
La palabra BASIC proviene de la expresión inglesa Beginner's All-purpose Symbolic Instruction Code: código de instrucciones
simbólicas de propósito general para principiantes.
El BASIC fue el primer lenguaje de programación desarrollado. Lo fue a mediados de la década de los sesenta por los profesores
John G. Kemeny y Thomas E. Kurtz en el Dartmouth College, en California. Su código se basa en el vocabulario inglés y en las
expresiones matemáticas. Consta de cientos de instrucciones para utilización de gráficos, procesado de textos, uso de variables,
archivos, etc. EL BASIC utiliza un alfabeto formado por los caracteres alfabéticos: A-Z, cifras 0-9, caracteres especiales como
operadores aritméticos: +, -, *, etc., y otros: (,),$, etc.
El lenguaje BASIC es, originalmente, un lenguaje interpretado. Existen dos tipos de lenguaje: interpretados y compilados. Los
interpretados son aquellos que necesitan del código fuente para funcionar (por ejemplo, GW-BASIC y QBasic). Los compilados,
convierten el código fuente en un archivo objeto y éste en un archivo ejecutable. Este es el caso del lenguaje C y de las versiones
más completas y recientes del BASIC.
Existen muchas versiones (implementaciones) del lenguaje BASIC. En el esquema siguiente se puede observar la evolución del
desarrollo de los diferentes lenguajes de programación y, entre ellos, la de BASIC.
1958 ALGOL 58
Intérprete orientado a la Inteligencia
1960 LISP
Artificial
sistema de TRAducción de FORmulas
1961 FORTRAN IV IBM
matemáticas
1961 COBOL 61 Extendido
1965 COBOL 65
1966 PL/I
sistema de TRAducción de FORmulas
1966 FORTRAN 66 IBM
matemáticas
1967 SIMULA 67
1968 ALGOL 68
1968 SNOBOL4
1970 APL/360
Centro de
1972 SMALLTALK Investigación de Xerox pequeño y rapido
en Palo Alto
1972 C Laboratorios Bell lenguaje con tipos
1974 COBOL 74
1990s C#
La mejor forma de aprender un lenguaje es programando con él. El programa más sencillo que se puede escribir en BASIC es el
siguiente:
Como podemos imaginar, este programa sin una sola instrucción no hace nada, pero se interpreta correctamente y nos da una
idea de que no se necesita mucho para empezar a programar en BASIC. Esto no es cierto en otros lenguajes como C, en los que
hay que utilizar obligatoriamente encabezados de programa y limitadores de bloques de sentencias.
Un programa algo más complicado, pero que hace algo, es el siguiente:
' Este es mi primer programa en BASIC
CLS
PRINT "Bienvenido a la programación en lenguaje BASIC"
END
Con él visualizamos en la pantalla el mensaje:
Bienvenido a la programación en lenguaje BASIC
En el programa se incluye la línea:
CLS
Esta línea constituye una sentencia. La sentencia consta únicamente de la instrucción CLS , y ésta produce el resultado de borrar
la pantalla.
La siguiente sentencia incluye la instrucción PRINT. Ésta toma como argumento una cadena de caracteres limitados por dobles
comillas " " y la imprime en la salida habitual, que generalmente es la pantalla del PC en el que trabajamos.
La instrucción END termina el programa. Ni siquiera es obligatorio finalizar con END, aunque es conveniente por una cuestión de
claridad. De cualquier manera, si extraemos esa sentencia, el programa funcionará exactamente igual (el programa finaliza
automáticamente cuando no se encuentran más líneas de código).
La inclusión de comentarios en un programa es una saludable práctica, como lo reconocerá cualquiera que haya tratado de leer un
listado hecho por otro programador o por sí mismo, varios meses atrás. Para el intérprete o el compilador, los comentarios son
inexistentes, por lo que no generan líneas de código ejecutable, permitiendo abundar en ellos tanto como se desee. En el lenguaje
BASIC se toma como comentario todo carácter que sigue a la comilla simple: ' o a la palabra clave REM.
Como se observa, un programa en QBasic es simplemente un fichero de caracteres que contiene un conjunto de instrucciones que
un programa especial, el intérprete, se encarga de transformar en un código que la computadora puede ejecutar (aunque no se
genera un archivo .EXE).
Antes de continuar hagamos un inciso sobre la nomenclatura utilizada en QBasic para designar a distintos elementos del lenguaje:
Elemento Definición
Sentencia Es una instrucción que realiza una operación. Se utilizan estas palabras de
Instrucción forma intercambiable. Se usa mucho la forma comando debido a su utilización
(Comando) en inglés.
Una palabra que forma parte del lenguaje QBasic. Cuando se utiliza una
Palabra clave palabra clave en una sentencia, QBasic automáticamente la convierte a
Keyword mayúsculas. No se puede utilizar una palabra clave para dar nombre a una
constante o variable (palabra reservada).
Cadena Una cadena de texto (caracteres). En Qbasic se delimita con comillas, por
String ejemplo, "Bienvenido". La cadena "" (vacía) es válida.
Designa a números enteros, decimales de precisión simple y decimales de
Número
precisión doble.
Un valor (cadena o número) que no cambia a lo largo de la ejecución del
programa. Hay dos clases de constantes; las constantes literales están
escritas directamente en el código: "Hola", 16; las constantes simbólicas o
Constante
con nombre son valores constantes a los que se les asigna un nombre. Por
ejemplo, LONG_MAX en lugar de 16. Las constantes simbólicas se definen
usando la palabra clave CONST.
Un contenedor con nombre para un número o una cadena. Son el medio para
que el programa "recuerde" datos. Se pueden crear variables de varias
Variable
maneras: calculando un valor, tomando una entrada de usuario, leyendo un
archivo, etc.
Designa una operación matemática. Los operadores pueden ser aritméticos,
Operador
relacionales o lógicos.
Devuelve una cadena o un número. Puede tomar uno o más parámetros de
Función
entrada para calcular el resultado.
No hace nada en el programa. Se utiliza como una nota explicativa que
Comentario
contribuye a clarificar el código y a recordar más tarde lo que se hizo.
Designa a un conjunto de líneas dentro de la estructura del programa, que
Bloque
guardan una relación de algún tipo entre sí.
Bucle Designa a un grupo de líneas que se ejecutan una serie de veces.
La estructura general de un módulo de código en QBasic consta de un programa principal y de varios subprogramas y/o funciones:
' Programa principal
declaración de variables
sentencias
END SUB
FUNCTION Funcion1 ( )
declaración de variables
sentencias
END FUNCTION
...
...
...
SUB Subprograman( )
declaración de variables
sentencias
END SUB
FUNCTION Funcionn ( )
declaración de variables
sentencias
END FUNCTION
Cuando la envergadura del programa es grande se suele fragmentar el módulo en varias partes, incluyendo cada parte en un
fichero separado. Normalmente colocaremos en cada fichero todas las subrutinas y funciones que se encarguen de una tarea del
programa. Por tanto, un programa en QBasic puede estar formado por diferentes módulos o fuentes. Es conveniente mantener
los fuentes de un tamaño no muy grande -para encadenar la ejecución de los diferentes módulos se utiliza la instrucción CHAIN
(CHAIN nombre.archivo$-.
• Introducción
• Identificadores, tipos y tamaños
• La instrucción LET
• Ámbito
Introducción
Si se deseara imprimir los resultados de multiplicar un número fijo por otro que adopta valores entre 0 y 9, la forma normal de
programar esto sería crear una constante para el primer número y un par de variables para el segundo y para el resultado del
producto. Una variable no es más que un nombre para identificar una (o varias) posiciones de memoria donde el programa guarda
los distintos valores de una misma entidad . En un programa BASIC es conveniente definir todas las variables que se utilizarán
antes de comenzar a usarlas, a fin de indicarle al intérprete o compilador de que tipo serán y, por tanto, cuánta memoria debe
destinar para albergar a cada una de ellas, aunque en QBasic no es obligatorio. Veamos un ejemplo:
' Multiplica dos números enteros
Correcto Incorrecto
cuenta 1cuenta
prueba23 prueba*
puerto.paralelo puerto_paralelo
El lenguaje QBasic no es sensible a mayúsculas y minúsculas (no es case sensitive), de modo que para el intérprete es lo
mismo el identificador cuenta que otro denominado Cuenta.
Los intérpretes y compiladores reservan determinados términos ó palabras claves (keywords), para el uso sintáctico del lenguaje,
tales como: CLS, PRINT, END, etc. y no se pueden utilizarla en nombres de variables.
Para crear una variable en un lugar determinado del un programa escribiremos primero el tipo de variable y luego el identificador
con el que queremos nombrar la variable. A esto se le denomina definir una variable. La forma general de la definición es:
DIM identificador [AS tipo]
DIM identificador[sufijo]
Por ejemplo:
DIM numero AS INTEGER ' crea la variable numero, de tipo número entero
DIM a!, b# ' crea dos variables a y b, de tipo número de precisión simple y doble, respect.
En QBasic, las variables no se pueden inicializar (es decir, establecer un valor inicial) en el momento de creación. Por ejemplo, es
incorrecto:
DIM numero% = 0 ' incorrecto, falla el intérprete
La asignación de valores a las variables hay que realizarla posteriormente a la definición de las mismas.
En QBasic, se pueden definir variables en cualquier parte de un programa.
Los tipos de datos atómicos definidos por QBasic son:
• cadenas de caracteres
• números enteros
• números en coma flotante
END
En él se definen dos variables single, se asigna un valor a la primera y se calcula la segunda mediante una expresión aritmética.
En la instrucción PRINT, el ; indica que se concatenen los valores a mostrar.
En Qbasic no es obligatorio definir el tipo de datos de una variable antes de utilizarla, aunque si es conveniente. De hecho, el
programa anterior también funciona así:
' Convierte grados Centígrados a Fahrenheit
END
En este caso es el intérprete el que asigna automáticamente el tipo de los datos a las variables. Esto facilita bastante la tarea de
programar, sobre todo a usuarios inexpertos, aunque no es lo más eficiente.
La instrucción LET
La sentencia LET asigna un valor a una variable. La sintaxis de uso es:
[LET] variable = expresión
expresión es una expresión del mismo tipo que la variable - número o string -. No se puede poner un valor string en una variable
numérica y viceversa. La palabra clave LET es opcional. En la mayor parte de los usos se prescinde de LET y de deja sólo variable
= expresión (es más claro y sencillo). Si se intenta poner un valor decimal en una variable entera el valor se redondea. Se pueden
poner valores enteros en variables Single y Double.
Ejemplos:
LET micadena$ = "Esto es una prueba."
mezcla# = i% + l& + s! + d#
Muestra Muestra
END END
SUB Muestra SUB Muestra
PRINT x1% PRINT x2%
END SUB END SUB
La palabra clave SHARED consigue que la variable x1 sea global, es decir, accesible en todo el código (todos los subprogramas)
del módulo. Por el contrario, x2 es local y sólo se conserva su valor en el programa principal, no siendo accesible desde los
subprogramas.
Otro ejemplo:
Variable Global Variable Local
' Muestra un número entero ' Muestra un número entero
Valor Valor
PRINT x1% PRINT x2%
END END
SUB Valor SUB Valor
SHARED x1% ' Aquí sólo se escribe SHARED, DIM x2%
' no DIM SHARED PRINT x2%
x1% = 100 END SUB
END SUB
PRINT "Hola"
PRINT "mundo"
END
El resultado es:
Hola
mundo
Nótese que PRINT imprime un salto de línea tras el texto. Se puede inhibir el salto automático de línea si se añade ; tras el texto:
' Muestra un mensaje
PRINT "Hola";
PRINT "mundo"
END
cuyo resultado es:
Hola mundo
Un ejemplo de uso con valores numéricos y de texto es:
' Muestra valores numéricos
a% = 50
b% = 100
END
cuyo resultado es:
El valor de a es 50 y el valor de b es 100
Nótese que al concatenar el texto con los números mediante ; se añade automáticamente un espacio en blanco antes de cada
valor numérico.
Si en lugar de utilizar ; se utiliza , para la concatenación:
a% = 50
b% = 100
END
el resultado es:
PRINT USING
Esta instrucción es similar a PRINT pero es capaz de dar un formato especificado de salida a los datos. La sintaxis de uso es:
PRINT USING formato; lista_de_expresiones
donde formato es una cadena de texto que contiene distintos especificadores que aplican formato a la lista_de_expresiones. Esta
lista no es más que un conjunto de expresiones numéricas o de texto concatenadas con ; o ,.
Los especificadores que se pueden utilizar en formato son:
PRINT
PRINT "Producto Cantidad Importe Importe Total"
PRINT "-------- -------- --------- -------------"
PRINT USING "\ \ ##,### ###,###.## #,###,###.##"; nombreitem$; numitems%; importeitem!; importetotal!
END
Este programa produce el resultado:
Introduzca el nombre del producto: relé
¿Cuántos elementos?: 30
¿Cuál es el importe unitario?: 1.5
LINE INPUT
Esta instrucción es sumamente similar a INPUT, si bien almacena en una sola variable toda la entrada proporcionada desde
teclado hasta encontrar un retorno de carro y no considera las comas (,) separadores de variables (como sucedía con INPUT).
Por ejemplo:
' Lee una cadena de caracteres desde el teclado
DIM frase AS STRING
LOCATE 20, 10
PRINT "Hola"
END
Obsérvese que primero se indica la fila (y) y luego la columna (x). La esquina superior izquierda es la posición (1, 1).
CLS
Ahora ya sólo resta saber cómo se limpia la pantalla. Ello es tan fácil como usar:
CLS
CLS
PRINT "Hola"
END
Subprogramas y Funciones
• Introducción
• Retorno de valores
• Paso de parámetros
• Declaración y comprobación de tipos
• Ejemplos
Introducción
Los subprogramas y funciones son rutinas, procedimientos o conjuntos de sentencias que realizan una labor específica. Los
subprogramas o subrutinas nacieron de la necesidad de no repetir innecesariamente un trabajo ya hecho. Pueden invocarse desde
el cuerpo del programa principal cuantas veces se desee. Están en el núcleo de lo que se denomina programación estructurada.
En QBasic existen dos clases de subrutinas o procedimientos:
• los subprogramas propiamente dichos (procedimientos SUB), que realizan un conjunto de tareas y no devuelven ningún
valor.
• las funciones (procedimientos FUNCTION), que devuelven un valor de un tipo que se puede especificar.
Los subprogramas y las funciones admiten parámetros (argumentos), que son datos que le pasan al procedimiento las sentencias
que la llaman.
La sintaxis habitual en la definición de un subprograma es:
SUB identificador [(lista_de_parámetros)]
bloque_de_código
END SUB
donde:
- identificador es el nombre del subprograma. Debe ser un identificador valido;
- lista_de_parámetros es una lista de variables, separadas por comas, que conforman los datos que le pasamos al
subprograma.
- bloque_de_código es un conjunto de sentencias.
hola
END
PRINT "Hola"
END SUB
que simplemente es una función que cuando es llamada imprime en pantalla un mensaje de saludo.
Cuando el programa al ejecutarse alcanza el cierre del procedimiento (END SUB), éste finaliza y devuelve el control al punto del
programa que lo llamó.
La sintaxis habitual en la definición de una función es:
FUNCTION identificador [tipo] [(lista_de_parámetros)]
bloque_de_código
nombre_de_la_función = expresión
bloque_de_código
END FUNCTION
donde:
- identificador es el nombre de la función. Debe ser un identificador valido;
- tipo es un sufijo [%, !, etc] o una expresión AS INTEGER, AS SINGLE, etc. que define el tipo de datos que devlelve
la función.
- lista_de_parámetros es una lista de variables, separadas por comas, que conforman los datos que le pasamos a la
función.
- nombre_de_la_función = expresión es una sentencia que produce que la función retorne el valor determinado por
expresión.
- bloque_de_código es un conjunto de sentencias.
El tipo es opcional. La lista de argumentos es también opcional. Podemos escribir como ejemplo:
' Ejemplo de uso de una función
' Función que suma dos enteros y devuelve la suma como otro entero
FUNCTION Suma% (s1%, s2%)
END FUNCTION
Cuando el programa al ejecutarse alcanza el cierre del procedimiento (END FUNCTION), éste finaliza y devuelve un valor de tipo
entero al programa que lo llamó.
Retorno de valores
Cuando la función finaliza hemos dicho que se devuelve un valor. Para obligar a la función a retornar un determinado valor se
utiliza la sentencia
nombre_de_la_función = expresión
lista% = 1
END FUNCTION
devuelve el entero 1 cada vez que es llamada. En QBasic podemos devolver cualquier tipo de datos de los llamados escalares.
Los tipos de datos escalares son los tipos numéricos y el tipo string. En QBASIC no se pueden devolver vectores (array).
END SUB
es una función que admite dos variables, una entera y otra de tipo cadena.
En los lenguajes de programación estructurada hay dos formas de pasar variables a una función:
• por referencia, o
• por valor
Cuando la variable se pasa por referencia, la función puede acceder a la variable original. Este enfoque es habitual en lenguajes
como el BASIC. (En C, sin embargo, todos los parámetros se pasan por valor. La función recibe una copia de los parámetros y
variables, y no puede acceder a las variables originales. Cualquier modificación que efectuemos sobre un parámetro no se refleja
en la variable original. Esto hace que no podamos alterar el valor de la variable por equivocación.)
Por ejemplo, el programa:
' Imprime valores
n% = 1
l$ = "A"
CLS
PRINT n%
imprime n%, l$
PRINT n%
END
numero% = 2
END SUB
da como resultado:
1
2 A
2
Es decir, la variable n, que originalmente valía 1, toma el valor 2 tras la llamada al procedimiento imprime.
declara una función que devuelve un carácter y tiene dos parámetros, un entero y un carácter.
NOTA:
DECLARE es requerido si se hace una llamada a un procedimiento FUNCTION o a uno SUB sin CALL (véanse los
ejemplos). QBasic generara automáticamente instrucciones DECLARE cuando se guarda un programa.
La lista de argumentos permite al intérprete/compilador hacer comprobación de tipos, ya que el tipo y numero de argumentos debe
coincidir en la declaración, definición y llamada a una función.
Véase, por ejemplo, el programa:
DECLARE FUNCTION imprime$ (numero%, char$) ' Declara la función "imprime"
' Ejemplo
DIM caracter AS STRING
CLS
imprime$ = letra
END FUNCTION
Ejemplos
Subprograma sin argumentos (no devuelve nada)
Este programa llama a la función BorraPantalla que despeja la pantalla mediante la orden CLS (clear screen) y muestra el
mensaje "la pantalla está limpia". Por supuesto, es de nula utilidad pero sirve para empezar.
DECLARE SUB BorraPantalla ()
SUB BorraPantalla
CLS
PRINT "La pantalla está limpia"
END SUB
compara num1, num2 ' Llamamos al subprogramas con sus dos argumentos
' También podríamos escribir: CALL compara(num1, num2)
END
IF a > b THEN
PRINT a; " es mayor que "; b
ELSE
PRINT b; " es mayor que "; a
END IF
END SUB
resultado = compara(num1, num2) ' Almacenamos en resultado el valor que devuelve la función
END
IF a > b THEN
compara% = a
ELSE
compara% = b
END IF
END FUNCTION
En este ejemplo podíamos haber hecho también:
PRINT "El mayor de los dos es "; compara(num1, num2)
De esta forma nos hubiésemos ahorrado tener que definir la variable resultado.
Expresiones
• Introducción
• La asignación
• Operadores
Introducción
Las expresiones son sentencias que tras realizar una determinada acción devuelven un resultado. Consideraremos a continuación
dos tipos fundamentales de expresiones:
• la asignación
• las que utilizan operadores
Asignación
El primer tipo a considerar dada su importancia es la asignación. La sintaxis de una asignación es:
[LET] variable = expresión
expresión es una expresión del mismo tipo que la variable -- número o string. No se puede poner un valor string en una variable
numérica y viceversa. La palabra clave LET es opcional. En la mayor parte de los usos se prescinde de LET y de deja sólo variable
= expresión (es más claro y sencillo). Si se intenta poner un valor decimal en una variable entera el valor se redondea. Se pueden
poner valores enteros en variables Single y Double.
Ejemplos:
LET micadena$ = "Esto es una prueba."
mezcla# = i% + l& + s! + d#
Operadores
El segundo tipo de expresiones son los operadores. Hay varios tipos de operadores:
• aritméticos
• relacionales y lógicos
• de manipulación de bits
Operadores aritméticos
Los cuales realizan las operaciones aritméticas básicas. Estas expresiones tienen como sintaxis:
num1 operador num2
j = b * 4 + 10 / 2
El valor que devuelve es de tipo entero: devuelve un 0 si el resultado de la comparación es falso y un -1 (no cero) si el resultado de
la comparación es verdadero. Cuando lo que comparamos son caracteres, se compara realmente su código ASCII.
Por ejemplo:
1>2 devuelve 0 (falso)
1=1 devuelve -1 (verdadero)
"a" < "b" devuelve -1 (verdadero)
(1 > 2) OR (1 = 1) devuelve -1 (verdadero)
NOT (1 = 1) devuelve 0 falso
Por supuesto, expresión1 y expresión 2 pueden contener variables, no sólo valores literales.
Los operadores Booleanos realizan un manejo de bits, es decir, operaciones Booleanas. Generan un valor verdadero (no cero) o
falso (cero) que puede ser utilizado al tomar una decisión.
Para el manejo de dichos bits, contamos con los operadores descritos en la siguiente tabla .
AND Y (bit a bit)
OR O inclusiva
XOR O exclusiva
NOT Complemento a uno
EQV Equivalencia
IMP Implicación
Estos operadores general los resultados esquematizados en la tabla siguiente ( V es verdadero -no cero- y F es falso -cero-):
expresión 1 expresión 2 AND OR XOR NOT EQV IMP
V V V V F V V V
F F F V V F F F
V V F V V F F V
F F F F F F V V
Las operaciones Booleanas se realizan después de las operaciones de las aritméticas y relacionales, en el orden de precedencia.
Como los operadores Booleanos realizan cálculos bit a bit, el uso de valores que no sean 0 para falso y -1 para verdadero puede
producir resultados inesperados.
Estos operadores muestran manipulan internamente, es decir bit a bit , las variables. Estos operadores sólo se aplican a
expresiones de tipo entero o entero largo, de modo que las expresiones se convierten en enteros antes de realizar una operación
booleana.
Describiremos mediante unos pocos ejemplos la operatoria de manejo de bits. Analicemos primero como funciona el operador
ANDSi suponemos tener dos variables del tipo char, una de ella de valor 85 (hex. 55 ), otra de valor 71 (hex. 47) y realizamos el Y
a nivel bits de ellas, obtendremos :
bits decimal hexadecimal
0 1 0 1 0 1 0 1 85 55
AND AND AND
0 1 0 0 0 1 1 1 71 47
------------------------- ------- -------
0 1 0 0 0 1 0 1 69 45
Nótese que la operación es del tipo lógico entre bits, por lo que los resultados numéricos tienen poco ó ningún significado y sólo se
han puesto con fines de ejemplo.
De la misma manera para la operación OR (O inclusiva), para las mismas variables anteriores obtendremos el resultado:
0 1 0 1 0 1 1 1 87 57
Analizando ahora la XOR (O exclusiva) tendremos, para las mismas variables anteriores:
0 0 0 1 0 0 1 0 18 12
Control de flujo
• Introducción
• La instrucción IF
• El bucle WHILE
• El bucle DO - WHILE
• El bucle FOR
• La instrucción EXIT
• La selección múltiple SELECT CASE
Introducción
En Qbasic las sentencias se ejecutan sucesivamente una tras otra (secuencialmente). Esto define un camino o dirección según la
cual se va desarrollado el programa. Sin embargo, habrá momentos en que el programa deba ejecutar determinadas partes
dependiendo del estado en el que se halle el propio programa o las variables externas. Esto permitir modificar el orden de la
ejecución para adaptarse al estado del programa y bifurcar hacia nuevas subrutinas cuando se cumplan ciertas condiciones, que el
programador fija de antemano. Los mecanismos en QBasic que permiten llevar esto a cabo son:
• la instrucción IF
• el bucle WHILE
• el bucle DO - WHILE
• el bucle FOR
• la instrucción EXIT
• la selección múltiple SELECT CASE
La instrucción IF
La primera sentencia de control es la sentencia if. Admite dos tipos de sintaxis:
IF expresión THEN sentencia_1 [ELSE sentencia_2]
o también:
IF expresión THEN
[bloque_sentencias_1]
[ELSEIF expresion_2 THEN
[bloque_sentencias_2]]...
ELSE
[bloque_sentencias_n]
END IF
Esta sentencia es equivalente a la que poseen la mayoría de lenguajes de programación y sirve para bifurcar en un punto de
programa. Permite al programa tomar decisiones. En su primera forma, la sentencia_1 sólo se ejecuta si el resultado de evaluar la
expresión es verdadero (no cero); en caso contrario, se ejecuta sentencia_2. En la segunda forma, tenemos varias posibilidades: si
al evaluar la expresión el resultado es verdadero se ejecutan las instrucciones bloque_sentencias_1, pero si el resultado es falso
se evalúa la expresión_2 y si ésta es verdadera se ejecuta bloque_sentencias_2, y así sucesivamente. En cualquier caso sólo una
de los bloques de sentencias se ejecuta.
Veamos algunos ejemplos:
IF num% = 1 THEN PRINT "la variable num vale 1" ELSE PRINT "la variable num no vale 1"
Tras evaluarse la expresión IF y ejecutarse la sentencia adecuada, el programa continúa con la línea siguiente a la de la última
sentencia del IF. Para la sentencia IF vale como expresión cualquiera válida en QBasic, incluso las llamadas a funciones:
IF suma(num1, num2) >= 0 THEN
PRINT "La suma de num1 y num2 es positiva"
END IF
Como sentencias valen cualquier tipo de sentencia válida en QBasic, entre ellas la propia sentencia IF. En este caso hablaremos
de sentencias IF anidadas. Por ejemplo:
IF num > 0 THEN
IF num = 1 THEN
PRINT "num es igual a 1"
ELSEIF num > 1 THEN
PRINT "num es mayor que 1"
ELSE
PRINT "num es menor que 1"
END IF
END IF
En este caso, si la variable num es menor o igual que cero el programa no mostrará ningún mensaje, y en caso contrario se
mostrará el mensaje correspondiente a la comparación del valor con la unidad.
El bucle WHILE
Un bucle es un conjunto de sentencias que se ejecutan repetidamente hasta que se alcanza una condición de fin de bucle, o
condición de salida. El bucle while es el tipo de bucle más sencillo. En su modo más simple se escribe:
WHILE expresión
bloque_sentencias
WEND
El bucle while comienza por evaluar la expresión. Si es cierta, se ejecuta bloque_sentencias. Entonces se vuelve a evaluar la
expresión. De nuevo, si es verdadera, se vuelve a ejecutar bloque_sentencias. Este proceso continúa hasta que el resultado de
evaluar la expresión es falso. Por esto se le llama a esta expresión la condición de salida. Por ejemplo:
variable% = 10
variable% = variable% -1
WEND
En este caso se imprime el valor de la variable hasta que se llega a 1. Normalmente, en las sentencias del bucle WHILE se coloca
alguna instrucción que modifique la expresión de control, como vemos en el ejemplo anterior.
El bucle DO - WHILE
La sintaxis de este bucle es:
DO [{WHILE | UNTIL} expresión]
bloque_sentencias
LOOP
o también:
DO
bloque_sentencias
LOOP [{WHILE | UNTIL} expresión]
Su funcionamiento es análogo el del bucle WHILE, salvo que la expresión de control se puede evaluar al final del bucle (si se
utiliza la segunda opción de sintaxis). Esto nos garantiza que el bucle DO_WHILE se ejecuta al menos una vez. Incluye también la
posibilidad de ejecutar el bucle mientras (WHILE) expresión sea verdadera o hasta (UNTIL) que expresión sea verdadera.
Por ejemplo:
n% = 9
DO
PRINT "número actual "; n%
n% = n% -1
LOOP WHILE n% >= 0
este programa muestra el valor de n hasta que vale 0. Y el siguiente produce el mismo resultado.
n% = 9
DO
PRINT "número actual "; n%
n% = n% -1
LOOP UNTIL n% = -1
El bucle FOR
La sintaxis del bucle FOR es:
FOR contador = inicio TO fin [STEP incremento]
bloque_sentencias
NEXT [contador]
Este bucle se utiliza para realizar un conjunto de acciones un número determinado de veces.Su versión más sencilla es:
FOR i% = 0 TO 10
PRINT "i vale "; i%
NEXT i%
Esta versión del bucle imprime el valor de i desde 0 con un incremento de una unidad mientras que esta variable no alcance el
valor 10.
FOR i% = 1 TO 10 STEP 2
PRINT "i vale "; i%
NEXT
Y en este ejemplo se muestran los valores 1, 3, 5, 7 y 9 (desde 1 con un incremento de 2).
El bucle FOR es equivalente a un bucle WHILE escrito del siguiente modo:
contador = inicio
WHILE contador <= fin
bloque_sentencias
contador = contador + incremento
WEND
Este bucle WHILE puede servirnos para salir fácilmente de dudas al escribir un bucle FOR, ya que se ve claramente el orden de
ejecución de las expresiones y sentencias dentro del bucle FOR. Como se ve, en cada pasada del bucle FOR se sigue el orden:
evaluación del valor del contador, ejecución de bloque_sentencias y e incremento del contador.
Las sentencia EXIT
Hay veces en que interesa romper un bucle en una determinada posición, para finalizar su ejecución. Esto suele ser habitual
cuando el bucle tiene una gran complicación o cuando necesitamos salir "por las malas" de él. Esto último suele ser frecuente
cuando en el bucle se producen "condiciones de error". Para este tipo de salto disponemos de la sentencia EXIT.
Su sintaxis es:
EXIT {DO | FOR}
La sentencia EXIT rompe la ejecución de un bucle o bloque de instrucciones y continúa en la instrucción que sigue al bucle o
bloque. Por ejemplo:
a% = 10
DO WHILE 1
PRINT a%
IF a% <= 1 THEN EXIT DO
a% = a% -1
LOOP
Aunque en apariencia este es un bucle sin fin, ya que la condición WHILE 1 es siempre cierta, este bucle se acaba cuando la
variable a valga 1. El bucle simplemente imprime su valor y decrementa la variable.
Otro ejemplo:
FOR i% = 1 TO 10
PRINT i%
INPUT a$
IF a$ = "S" THEN EXIT FOR
NEXT
el cual imprime enteros entre 1 y 10 hasta que se introduce por teclado la la pulsación S.
EXIT también se utiliza con procedimientos SUB o FUNCTION, para abandonar el procedimiento antes de ejecutar todas las
sentencias que preceden al correspondiente END {SUB | FUNCTION}.
Su sintaxis es más complicada que la de anteriores bucles, ya que agrupa un mayor número de acciones y posibilidades en una
sola sentencia. El modo de funcionamiento es el siguiente:
• primero se evalúa la expresión de control.
• A continuación se compara con lista_expresiones_1 de la primera etiqueta CASE. Si son iguales, se ejecuta
bloque_sentencias_1. Si no, se compara con lista_expresiones_2, y así sucesivamente.
• Se repite el proceso hasta agotar todas las etiquetas case. Si al llegar a la etiqueta ELSE no se ha ejecutado ninguna
sentencia ésta es la acción por defecto. La etiqueta ELSE es opcional. Si no la ponemos el programa simplemente salta
fuera del SELCT CASE.
Vamos a ver un ejemplo de múltiples casos con IF y luego con SELECT CASE:
' Ejemplo de selcción con IF
DIM num AS INTEGER
IF num = 1 THEN
PRINT "Es un 1"
ELSEIF num = 2 THEN
PRINT "Es un 2"
ELSEIF num = 3 THEN
PRINT "Es un 3"
ELSE
PRINT "No es ni 1, ni 2, ni 3"
END IF
END
Ahora con SELECT CASE:
' Ejemplo de selección con SELCT CASE
DIM num AS INTEGER
• expresión TO expresión
• IS operador_relacional expresión
• Introducción
• Declaración
• Inicialización
• Arrays de más de una dimensión
• Paso de un array a una función
Introducción
Una posible definición de array sería:
"Un conjunto de datos del mismo tipo, identificados por el mismo nombre, y que se pueden distinguir mediante un
número de índice."
Pero ¿qué quiere decir esto y para qué lo queremos?. Pues bien, supongamos que queremos almacenar la temperatura media de
cada hora del día y la temperatura promedio del día. Con lo que sabemos hasta ahora podríamos hacer algo así:
' Declaramos 24 variables, una para cada hora del día
DIM temp1!, temp2!, temp3!, temp4!, temp5!, temp6!, temp7!, temp8!
DIM temp9!, temp10!, temp11!, temp12!, temp13!, temp14!, temp15!, temp16!
DIM temp17!, temp18!, temp19!, temp20!, temp21!, temp22!, temp23!, temp0!
DIM media!
No hay que confundirse. En la declaración del array el número entre corchetes es el número total de elementos; en cambio,
cuando usamos la matriz, el número entre corchetes es el índice.
Declaración de un array
La forma general de declarar un array es la siguiente:
DIM identificador_del_array[sufijo_tipo_dato](dimensión) [AS tipo_de_dato]
donde:
• el sufijo_tipo_dato o tipo_de_dato indican uno de los tipos de datos conocidos (%, !, INTEGER, SINGLE, etc). En el
ejemplo era SINGLE (!)
• El identificador_del_array es el nombre que le damos (en el ejemplo era temp).
• La dimensión es el número de elementos que tiene el array.
Como se ha indicado antes, al declarar un array reservamos en memoria tantas variables del tipo_de_dato como las indicada en
dimensión.
dimensión también se puede especificar dando los límites superior e inferior de los subíndices del array:
DIM identificador_del_array[sufijo_tipo_dato]([inferior TO] superior)
En el ejemplo anterior podríamos haber puesto también:
DIM temp(0 TO 23) AS SINGLE ' Con esto declaramos las 24 variables
Inicialización de un array
En QBasic se inicializan los arrays al asignar valores a cada elemento de los mismos. Es decir, por ejemplo:
temp!(9) = 20
temp!(12) = 25
temp!(20) = 23
Ahora el elemento 10, es decir, temp!(9), valdrá 20. El elemento 13 valdrá 25, y el elemento 21 valdrá 23. El resto, si no se
asignan, tomarán valor 0 por defecto. Por ejemplo, el programa:
DIM temp!(24), hora%
temp!(9) = 20
temp!(12) = 25
temp!(20) = 23
FOR hora% = 0 TO 23
PRINT "La temperatura a las";hora%;" era de"; temp!(hora%);"grados."
NEXT hora%
dará como resultado:
La temperatura a las 0 era de 0 grados.
La temperatura a las 1 era de 0 grados.
La temperatura a las 2 era de 0 grados.
La temperatura a las 3 era de 0 grados.
...
La temperatura a las 9 era de 20 grados.
...
La temperatura a las 12 era de 25 grados.
...
La temperatura a las 20 era de 23 grados.
La temperatura a las 21 era de 0 grados.
La temperatura a las 22 era de 0 grados.
La temperatura a las 23 era de 0 grados.
Vemos que los elementos a los que no se ha asignado valor inicial son nulos
o también:
DIM matriz(inferior_1 TO superior_1, inferior_2 TO superior_2)
Y para acceder al elemento caracterizado por los subíndices i,j de la matriz no hay más que escribir la expresión matriz(i,j).
Esto es generalizable a más dimensiones.
FOR contador% = 1 TO 10
matriz(contador%) = 2*contador% ' Asigna valores a los elementos
PRINT contador%, matriz(contador%)
NEXT contador%
PRINT "La suma es "; sumar(matriz())
END
FUNCTION sumar%( m() AS INTEGER ) ' El argumento es el array m() sin especificar la dimensión
suma% = 0
FOR i% = 0 TO 10
suma% = suma% + m(i%)
NEXT i%
sumar = suma%
END
Este programa muestra los 10 elementos de un array y halla su suma. Obsérvese que en el argumento de la función sumar se
especifica el array pero sin dimensiones, para que tome la dimensión del array utilizado en la llamada al procedimiento en el
programa principal.
Manejo de archivos
Los archivos o ficheros brindan una forma de guardar permanentemente los datos y resultados de nuestros programas.
Es importante indicar que los ficheros no son únicamente los archivos que guardamos en el disco duro. En QBasic algunos
dispositivos del ordenador (como el puerto serie de comunicaciones) se tratan como ficheros.
En el ejemplo usábamos:
OPEN "origen.txt" FOR INPUT AS #1
El nombre de fichero se puede indicar directamente (como en el ejemplo) o usando una variable y se puede abrir de diversas
formas. Esto se especifica con el parámetro modo. Los modos posibles son:
especifica que el archivo va a ser abierto para leer información
INPUT
de forma secuencial.
especifica que el archivo va a ser abierto para escribir información de forma
OUTPUT
secuencial.
especifica que el archivo va a ser abierto en el modo de acceso
RANDOM
aleatorio. RANDOM es el modo de archivo predeterminado.
especifica que el archivo va a ser abierto para añadir información de salida
APPEND secuencial y coloca el puntero de archivo al final del archivo. Una instrucción PRINT #
o WRITE # añade la información al archivo.
especifica el modo de archivo binario. En este modo, es posible
BINARY leer o escribir información en cualquier posición de byte del archivo usando
instrucciones GET o PUT.
nº_archivo es un identificador que permite distinguir los distintos ficheros que se utilizan, cuando se usan varios simultáneamente.
Esta función comprueba si se ha llegado al final de nº_archivo, en cuyo caso devuelve un valor verdadero (no 0). Si no se ha
llegado al final de fichero devuelve falso (0). Por eso lo usamos del siguiente modo:
DO WHILE NOT EOF(1)
o
DO UNTIL EOF(1)
Esta función lee desde el fichero nº_archivo el número de bytes especificado por nº_caracteres.
Por ejemplo, el siguiente programa muestra todo el contenido del fichero "origen.txt" byte a byte.
' Lee un archivo de texto carácter a carácter
DIM letra AS STRING*1
OPEN "origen.txt" FOR INPUT AS #1 ' Abre el archivo origen para lectura
OPEN "destino.txt" FOR OUTPUT AS #2 ' Abre el archivo destino para escritura
CLOSE #1, #2
END
Como en el caso de la lectura de archivos, analizaremos este ejemplo poco a poco deteniéndonos en:
• Apertura del fichero para escritura: OPEN
• Escritura de caracteres en el fichero: PRINT #
• Comprobación de fin de fichero
• Cierre del fichero: CLOSE
Apertura del fichero para escritura: OPEN
El siguiente paso, como antes, es abrir el fichero usando OPEN. La diferencia es que ahora tenemos que abrirlo en modo escritura.
Usamos el modo OUTPUT (crea el fichero, o lo vacía si existe) porque queremos crear un fichero:
OPEN "destino.txt" FOR OUTPUT AS #2
Sin embargo, WRITE inserta comas (,) entre los datos y comillas (") alrededor de cadenas de texto. Para notar la diferencia
considérese el siguiente ejemplo:
OPEN "destino.txt" FOR OUTPUT AS #1
CLOSE #1
Como resultado, en el archivo "destino.txt" se escribirá:
1 2 Tecnología
1,2,"Tecnología"
GET y PUT
GET lee información de un archivo colocándola en un buffer de acceso aleatorio o en una variable.
PUT escribe una variable o un buffer de acceso aleatorio en un archivo.
La sintaxis es:
GET [#]numarchivo%[,[numregistro&][,variable]]
PUT [#]numarchivo%[,[numregistro&][,variable]]
Por ejemplo:
TYPE RegistroPrueba ' Define un tipo de datos con un texto de 20 caracteres y un número de precisión simple
Alumno AS STRING * 20
Nota AS SINGLE
END TYPE
DIM MiClase AS RegistroPrueba ' Declara una variable edl tipo anterior
La instrucción SEEK establece la posición del archivo para la siguiente acción de lectura o escritura:
SEEK [#]nº_archivo%, posición&
FOR i% = 1 TO 10
PUT #1, , i%
NEXT i%
• Introducción
• Acceso a los puertos hardware
• Acceso a la memoria
Introducción
Para intercambiar información con dispositivos exteriores, el computador utiliza los puertos de entrada y salida (E/S). Estos puertos
se caracterizan por la dirección que tienen asignada en el mapa de memoria, y es posible la comunicación con los mismos
enviando o recogiendo bytes a/en dicha dirección. Así, nos centraremos ahora en las funciones de acceso a los puertos hardware
que proporciona Qbasic.
Al igual que en determinadas circunstancias es preciso comunicarse con dispositivos externos, también es necesario intercambiar
información con el propio PC. Ello se realiza con frecuencia leyendo y escribiendo valores en/a determinadas posiciones de la
memoria del mismo. Por ejemplo, podemos conocer el estado en el que se encuentra el teclado del PC sin más que acceder al
valor almacenado en el segmento 0x40, offset 0x17 de la memoria. Con él podemos discernir si la tecla "bloq mayús" está pulsada
o no, si la tecla "Alt" está pulsada o no, etc. Asimismo, podemos recoger información del hardware actualmente instalado en el PC
y, entre otras cosas, determinar en qué direcciones de E/S se hallan los puertos hardware mencionados en el párrafo anterior. Así
existen en QBasic algunas funciones que proporcionan acceso a la memoria.
donde:
puerto_dir es la dirección (valor entero: 0-65.535) que identifica el puerto hardware de la cual se quiere leer y valor%
y es una variable entera en la que se almacena el byte leído (0-255).
En el siguiente ejemplo vamos a obtener un byte del puerto paralelo (bidireccional) instalado en el PC (en la dirección de E/S
378h):%
' Lee un byte del puerto paralelo
DIM valor AS INTEGER
DIM puerto AS INTEGER: puerto = &H378 ' dirección del puerto paralelo
valor = INP(puerto)
PRINT "El byte leído del puerto "; puerto; " es "; valor
END
Escritura en el puerto
Para enviar información a un puerto hardware (escritura en el puerto), Qbasic proporciona la función OUT. Esta función envía un
byte a un puerto (hardware) de E/S.
La sintaxis de la función es:
OUT puerto_dir%, valor%
donde:
• puerto_dir es la dirección del puerto hardware en la cual se quiere escribir (un entero: 0-65.535);
• valor es el byte (0-255) que se envía al puerto.
En el siguiente ejemplo vamos a enviar la letra C al primer puerto paralelo bidireccional instalado en el PC (en la dirección de E/S
378h):
' Envía un carácter al puerto paralelo
DIM valor AS INTEGR
DIM puerto AS INTEGER: puerto = &H378 ' dirección del puerto paralelo
valor = ASC("C") ' valor contiene el código ASCII de la letra C (el entero: 67)
Acceso a la memoria
• Lectura de la memoria
• Escritura en la memoria
Lectura de la memoria
Para leer la información almacenada en la memoria, QBasic proporciona la función PEEK. Ésta devuelve el valor de byte
almacenado en la posición de memoria designada por segmento:offset (direccionamiento segmentado de la memoria).
Esta función se declaran de la siguiente manera:
valor% = PEEK(dirección%)
donde:
• dirección es la posición de memoria relativa a la dirección del segmento actual, establecida por DEF SEG
(dirección es un entero: 0-65.535)
• valor es el byte (0-255) que se lee de la memoria.
NOTA: DEF SEG establece el segmento de memoria sobre el que se realizará la operación de lectura (un valor entre
0 y 65.535). Por ejemplo DEF SEG = 0.
Como ejemplo, veamos cómo se determina cuántos puertos paralelo se hallan instalados en un PC, y qué direcciones de E/S
tienen asignadas. Para ello, es preciso leer en la posición de memoria 408h una tabla de 3 palabras de 16 bits (2 bytes) que
contienen las direcciones de los puertos paralelo presentes en el sistema:
' Determina los puertos paralelo instalados en el PC y sus direcciones
NEXT puerto%
END
Escritura en la memoria
Para almacenar un dato en la posición de memoria designada por segmento:offset, QBasic proporciona la función POKE. Ésta
almacena un carácter (1 byte).
La sintaxis de la función es:
POKE dirección%, valor%
donde:
• dirección es la posición de memoria relativa a la dirección del segmento actual, establecida por DEF SEG (dirección es un
entero: 0-65.535)
• valor es el byte (0-255) que se desea escribir en la dirección de memoria especificada.
Como ejemplo, veamos cómo se fuerza por software la activación de "Bloq Mayús". Para ello hay que cambiar el bit 6 de la
posición 417h, lugar de las variables de la BIOS donde residen los banderines de estado del teclado:
' Cambia el estado de Bloq Mayús
DEF SEG = 0
Trataremos de dar unas breves indicaciones acerca de cuál es la forma más correcta de programar. Qué aspecto dar al código
fuente para que sea más legible y elegante, cómo distribuir el código fuente, etc
Los comentarios
El código fuente debe estar bien documentado, de tal forma que si se lo pasamos a otra persona pueda entenderlo sin grandes
dificultades. Quizá se piense: "mi código es mío y nunca se lo voy a dejar a nadie, así que para que voy a comentarlo". Parece
lógico, pero imagínese que se abandona temporalmente y en el futuro se quiere retocar el programa. Es muy probable el olvido de
por qué se hizo tal o cual cosa, (pasa muy a menudo) y es preciso gastar un montón de tiempo descifrando algo que en su día
estaba entendido perfectamente.
Aquí está un ejemplo de un programa mal comentado:
' Empiezo el programa
DIM cadena AS STRING, i AS INTEGER ' declaro una variable llamada cadena y otra llamada i
PRINT "Introduce una cadena: " ' Imprimo el mensaje 'Introduce una cadena'
INPUT "", cadena ' Pregunto por el valor de cadena
FOR i=1 TO LEN(cadena) ' Muestra cada carácter hasta la longitud de la cadena
PRINT MID$(cadena, i, 1)
NEXT i
END
Este programa es tan sencillo que no tiene puntos oscuros para comentar.
Es importante indicar para qué se van a usar las variables. Cuando tengamos muchas y pase el tiempo es difícil descifrar para que
era cada una.