Está en la página 1de 22

Programación en C++/Estructuras

De Wikilibros, la colección de libros de texto de contenido libre.

< Programación en C++

Saltar a navegación, buscar

← Iteraciones y Funciones
decisiones →

Contenido
[ocultar]

• 1 Estructuras de datos
o 1.1 Estructuras básicas en C, C++
 1.1.1 variables
o 1.2 Matrices
 1.2.1 Matrices estáticas
 1.2.2 Acceso a los miembros de una arreglo de datos:
 1.2.3 Arreglos dinámicos
o 1.3 Estructuras compuestas (struct, union, class)
 1.3.1 Acceso a los miembros de una estructura
 1.3.2 Estructuras anidadas
 1.3.3 Herencia
 1.3.4 Estructura de campos de bits
o 1.4 union: Sintaxis general
o 1.5 class: sintaxis

o 1.6 struct vs. class

[editar] Estructuras de datos


Las estructuras de datos se emplean con el objetivo principal de organizar los datos
contenidos dentro de la memoria de la PC. Así, nuestra primera experiencia con estructuras
comienza desde el momento mismo en que usamos en nuestros programas variables de
tipos primitivos (char, short, int, float, etc). A la memoria de la PC la podemos considerar
como un enorme bloque compuesto por una serie de BYTES dispuestos secuencialmente
uno despues del otro, por ejemplo, si nuestro computador posee una memoria de 128MB
(128 megas) entonces podemos leer o escribir desde el BYTE 0 hasta el BYTE 128MB - 1 (
0000000H .. 7FFFFFFH ).
La idea de ver la memoria como un serie de bytes es buena, sin embargo no es suficiente ya
que en la misma podemos guardar números, cadenas de caracteres, funciones, objetos, etc.
de tal manera que surge la necesidad de establecer los mecanismos adecuados para dar
cuenta de la forma, tamaño y objetivo de los datos almacenados. Según el tipo de
microprocesador, estos tienen la capacidad para manipular o direccionar estructuras
compuestas por uno, dos, cuatro, etc, bytes; de donde se derivan los tipos que comunmente
se conocen como: BYTE, WORD, DWORD, QWORD y TWORD.

La estructura mínima de información manipulable en un sistema de memoria de


computadoras es el BIT el cual se agrupa normalmente en bloques de 8 para formar un
BYTE. Cabe mencionar que los BITS no son direccionables directamente, sino a travez de
compuertas AND, OR, NOT, XOR, mismas que en C,C++ se escriben como &, |, ~ y ^
conocidos como "Bitwise operators".

En C,C++ existe una serie de estructuras básicas o tipos primitivos, los cuales pueden ser
usados por el programador para declarar variables, y también son el fundamento sobre el
cual se crean estructuras complejas. El tamaño de los tipos primitivos no es estándar ya que
los mismos dependen de factores tales como:

• Tipo del microprocesador


• El compilador

Sin embargo, en la actualidad (año 2007) la mayoria de compiladores de C,C++ soportan


los siguientes tipos con la longitud indicada:

[editar] Estructuras básicas en C, C++


Tipos primitivos

Nombre común Nombre C Longitud

BYTE char 8 bits

WORD short 16 bits

DWORD int 32 bits

DWORD long 32 bits

DWORD float 32 bits

QWORD double 64 bits


TWORD long double 80 bits

Nota: en el lenguaje C,C++ existe el operador sizeof(), con el cual se puede obtener el
tamaño (número de bytes) ocupados por un tipo específico. Por ejemplo, sizeof(int) regresa
el número de bytes ocupados por lo datos de tipo int.

[editar] variables
En C, C++ la sintaxis para declarar variables es:

tipo id1 [, id2 ...] ;

donde, tipo se refiere a uno de los tipos mostrados en la tabla anterior; id1 es el nombre con
el cual se identificará a la variable. Observe que si se quiere declarar más de una variable en
una línea de instrucción, las mismas deben separarse por medio de una coma.

Ejemplos:

char c;
int i;
float f;
int x,y,z;

D memoria y con la idea de referirnos a los mismos mediante nombres usamos


identificadores de variables.

[editar] Matrices
Una Matriz (en inglés, array) es una estructura usada para agrupar bajo
un mismo nombre
listas de datos de un mismo tipo.

El tipo de matriz puede ser cualquiera, sin embargo cada componente tiene que ser del
mismo tipo. El C estándar solamente da soporte para matrices estáticas, mientras que con
C++ se pueden crear matrices dinámicas a raiz de la librería estándar de plantillas (STL).

[editar] Matrices estáticas

Una matriz estática es una estructura cuyo tamaño es determinado en tiempo de


compilación, es decir, una vez establecido el tamaño de la matriz ésta no podrá cambiarse
durante el tiempo de ejecución. En C,C++ para declarar un arreglo estático de datos se
emplea la sintaxis:

tipo identificador[ [tamaño] ] [ = { lista de inicialización } ] ;


donde,

• tipo se refiere al tipo de datos que contendrá el arreglo. El tipo puede


ser cualquiera de los tipos estándar (char, int, float, etc.) o un tipo
definido por el usuario. Es más, el tipo del arreglo puede ser de una
estructura creada con: struct, union y class.

• identificador se refiere al nombre que le daremos al arreglo.

• tamaño es opcional e indica el número de elementos que contendrá el


arreglo. Si un arreglo se declara sin tamaño, el mismo no podrá contener
elemento alguno a menos que en la declaración se emplee una lista de
inicialización.

• lista de inicialización es opcional y se usa para establecer valores


para cada uno de los componentes del arreglo. Si el arreglo es declarado
con un tamaño especifíco el número de valores inicializados no podrá ser
mayor a dicho tamaño.

Ejemplos:

int intA[5];
long longA[5] = { 1, 2, 3, 4, 5 };
char charA[] = { 'a', 'b', 'c' };

[editar] Acceso a los miembros de una arreglo de datos:

En orden de acceder a los miembros de un arreglo se debe indicar el nombre del arreglo
seguido de dos corchetes, dentro de los cuales se debe especificar el índice del elemento
deseado. Se debe aclarar que los índices son números o expresiones enteras y que en C,C++
estos tienen un rango permitido de 0 a T-1 ( T = tamaño del arreglo ).

Ejemplos: dados los arreglos intA, charA, longA ( ejemplo anterior )

intA[0] = 100; // establece el valor del elemento 0 de intA a 100.

charA[3] = 'O'; // establece el valor del elemento 3 de charA a 'O'.

cout << longA[0]; // despliega el elemento 0 de longA.

[editar] Arreglos dinámicos

Un arreglo dinámico es una estructura compleja y, ya que el C estándar no da el soporte


para operar con estos tipos de estructuras, le corresponde al programador crear los
algoritmos necesarios para su implementación. Crear lista dinámicas de datos en C estándar
no es una tarea para programadores inexpertos, ya que para lograr tal objetivo se necesita
tener conocimentos solidos acerca de los punteros y el comportamiento de los mismos. Los
usuarios de C++ pueden auxiliarse de la librería estándar de plantillas, conocidas por sus
siglas en ingles como STL.
[editar] Estructuras compuestas (struct, union, class)
Con base en los tipos básicos mostrados arriba, se pueden crear nuevos tipos con
estructuras compuestas por uno o más de uno de los tipos mencionados. En C, C++ en
orden de crear nuevas estructuras se emplean la palabras reservadas struct, union y class.

• struct: esta orden se emplea para agrupar variables de tipos iguales o


diferentes en un solo registro, con la misma se pueden crear estructuras
anónimas, estructuras con nombre, y un tipo especial de estructura
conocida como bit-fields ( banderas o campos de bits ).

• union: una union es similar a una struct, salvo que en una estructura
creada con union los campos o variables comparten una dirección de
almacenamiento común.

• class: una clase es una estructura en donde se agrupan variables y


funciones, la misma es usada en Programación Orientada al Objeto. Las
clases no son soportadas por el C estándar.

Nota: tanto las estructuras como las uniones y las clases pueden ser
anónimas, pero lo más
recomendable es darle a las mismas un nombre. Si una estructura, union o
clase posee
nombre, esta pueden ser empleadas para declarar variables de la misma y,
lo más importante,
puede ser usada para el paso de parámetros a funciones.

Sintaxis general: struct


struct [ <nombre tipo de estructura > ] {
[ <tipo> <nombre-variable[, nombre-variable, ...]> ] ;
[ <tipo> <nombre-variable[, nombre-variable, ...]> ] ;
...
} [ <variables de estructura> ] ;

Nota: recuerde que lo que se muestra entre corchetes es opcional.

struct: Sintaxis ( variación uno, estructura anónima )

De acuerdo con la sintaxis general de la orden struct es posible crear estructuras de datos
anónimas. Solamente hay que tener en cuenta que en una declaración anónima se debe
definir al menos una variable al final de la declaración. Por ejemplo, con el siguiente
fragmento de código:

struct { int a, b; } p1;


se declara y define la variable estructurada p1, misma que se compone por los miembros a
y b; ambos del tipo int. Ahora bien, la sintaxis mostrada arriba no es tan común ni
conveniente, ya que con la misma solamente se esta creando una variable estructurada pero
no un nuevo tipo. Es decir, si desearamos tener otra variable que tuviera las mismas
caracteristicas que posee la variable p1, necesitariamos escribir exactamente la misma
instrucción, salvo que cambiando el nombre de la variable. Por ejemplo:

struct { int a, b; } p2;

Por supuesto, en una misma línea de instrucción podemos definir más de una variable.
Ejemplo:

struct { int a, b; } p1, p2;

Entonces, para crear nuevos tipos con struct deberemos de modificar la sintaxis mostrada
en los ejemplos anteriores.

Sintaxis: struct ( variación dos, estructura con nombre )

Observe que, la sintaxis para declarar estructuras con nombre es bastante parecida a la
sintaxis para declarar estructuras anónimas; salvo que una declaración de estructura con
nombre se debe especificar el nombre deseado para la misma. Además, en una declaración
de estructura con nombre la o las variables definidas al final de la misma son opcionales.

Ejemplos:

struct pareja { int a, b; } p1;

En el fragmento de código anterior se declara la estructura identificada como pareja, misma


que se compone de los miembros a y b, ambos de tipo int. En el mismo ejemplo, se define
la variable p1; la cual es una variable estructurada de tipo pareja.

Una vez que una estructura con nombre ha sido creada, la misma puede ser usada para
declarar cualquier número de variables. Por ejemplo, en el siguiente fragmento de código se
crea la estructura tiempo compuesta por los miembros hora, minuto y segundo; todos del
tipo int. En el mismo ejemplo, se declaran las variables t1 y t2.

/* declaración de estructura tiempo */


struct tiempo { int hora, minuto, segundo; };

/* declaración de variables de tipo tiempo */


struct tiempo t1, t2;

Nota: en C++ puede obviarse la palabra struct a la hora de declarar variables. Así, en C++
la línea de instrución struct tiempo t1, t2; ( del ejemplo anterior) puede escibirse como:
tiempo t1, t2;
[editar] Acceso a los miembros de una estructura

En orden de poder leer o escribir uno de los miembros de una variable estructurada se debe
usar el operador de acceso ( . ), o sea, el nombre de la variable seguida por un punto
seguido por el nombre del miembro o componente deseado de la estructura. Por ejemplo,
para acceder a los miembros de la variable t1 (mostrada arriba) podemos hacerlo de la
siguiente manera:

t1.hora = 12;
t1.minuto = 0;
t1.segundo = 0;

printf ("%i\n", t1.hora);


cout << t1.minutos << endl;

[editar] Estructuras anidadas

Los miembros de una estructura pueden ser ellos mismos otra estructura previamente
identificada o bien una estructura anónima. Por ejemplo, en el siguiente fragmento de
código se crean las estructuras pareja y pareja2. Observese cómo dentro de los miembros de
pareja2 se declara el miembro X, mismo que es una estructura del tipo pareja. Luego, las
variables declaradas a raiz de la estructura pareja2 poseerán los miembros variables a y b
heredados de pareja, y c.

struct pareja { int a, b ; };


struct pareja2 { struct pareja X; int c; } P3;

Ahora bien, para acceder a los miembros de una estructura dentro de otra estructura se
emplea el mismo mecanismo de acceso (el punto). Por ejemplo, para desplegar el miembro
a de la variable P3 declarada en el ejemplo anterior, lo haremos más o menos así:

printf( "%i\n", P3.X.a );

[editar] Herencia

El termino herencia se usa con gran frecuencia en Programación Orientada al Objeto, y se


le relaciona principalmente con las clases. Sin embargo, la herencia está presente siempre y
cuando una estructura "struct", "union" o "class" posea a otra estructura. En ese sentido, en
C++ se presentan dos tipos de herencia:

• herencia por agregación o composición.


• herencia por extensión.

Por ejemplo, en la definicion de las estructuras pareja y pareja2 del ejemplo anterior, se
dice que pareja2 hereda por composición todos los miembros de pareja. Ahora, en el
siguiente ejemplo se usa la sintaxis para que la estructura pareja2 herede por extensión los
miembros de pareja:
// solo C++
struct pareja { int a, b ; };
struct pareja2 : pareja { int c; } P3;

[editar] Estructura de campos de bits

Un campo de bit es un elemento de una estructura definido en terminos


de bits. Usando un tipo especial de definicion de struct, se pueden
declarar elementos de estructura con rangos de 1 a 16 de largo.
(dependiendo de la arquitectura de la PC y del compilador, el rango para
una estructura de campos de bits puede ser de 1 a 16, 1 a 32, 1 a 64).

Antes de ver un ejemplo del uso de struct para crear estructuras de campos de bits
consideremos el caso en donde se tiene una variable del tipo short (16 bits) y que para la
misma se desea que los bits tengan significados especificos. digamos que el primer bit
servirá para controlar alguna condición; los siguientes cuatro bits, o sea del segundo al
quinto bit, controlarán otra condición; el bit 6 tendrá otra funcion; y el resto, o sea del
septimo al decimosexto bit se emplearán para contralar otra condición. De tal manera que si
queremos, por ejemplo, saber si el primer bit de la variable tiene almacenado un 1 o un 0
podemos emplear la siguiente sintaxis:

int X = 123;
int r = X & 1;

la cosa parece sencilla, pero ahora consideremos el caso en el cual deseamos saber cual es
el valor contenido por el grupo de bits ( segundo al quinto ), entonces nos daremos cuenta
que no basta con una prueba mediante AND ( X & 1 ) sino que hay que realizar otros pasos.

Precisamente, para problemas como el planteado arriba es que el lenguaje C,C++ da


soporte a las estructuras de campos de bits. Por ejemplo, la estructura

struct campo_de_bit {
int bit_1 : 1;
int bits_2_a_5 : 4;
int bit_6 : 1;
int bits_7_a_16 : 10;
} bit_var;

corresponde a la siguiente colección de campos bits:


El mecanismo de estructuras de campos de bits soportado por C,C++ es una herramienta
útil y poderosa, sobre todo en programación de bajo nivel; ya que mediante el mismo es
posible aislar y dar nombres a todos y cada de los bits de un dato y también crear en un
mismo campo grupos de bits (como se muestra arriba). Ahora bien, no hay que olvidar que
la estructura minima de información en un sistema de memoria de una PC es el bit, y que
para aislar a cada uno de estos se puede emplear el operador AND ( &, en C ), pero
mediante el mecanismo mencionado el compilador genera los algoritmos necesarios para
llevar a cabo el aislamiento de los bits. Por ejemplo, para escribir y leer bit identificado
como bit_1 de la variable bit_var del ejemplo anterior, podemos emplear las siguientes
instrucciones:

bit_var.bit_1 = 1;
printf("%i\n", bit_var.bit_1 );

Nota: acerca de las estructuras de campos de bits hay que hacer la aclaración que, aunque
cada uno de los campos de la estructura pueden declarse como enteros con signo o enteros
sin signo, la misma no tendrá una longitud mayor a un entero largo.

[editar] union: Sintaxis general


union [ <nombre tipo de union > ] {
<tipo> <lista de variables>;
} [ <variables de union> ] ;

• De la misma manera que con la orden struct, con la orden union se


pueden crear estructuras con nombre y estructuras sin nombre.

• El mecanismo de acceso a los miembros de una union es igual al


mecanismo de acceso a los miembros de una struct.

• Los miembros de una union comparten un espacio de almacenamiento


común.

• En una union, el compilador reserva el espacio de almacenamiento para


la misma de acuerdo con el el tipo de la variable de mayor tamaño.
Ejemplo: union anónima
union { short a; long b; } u1;

En el ejemplo anterior se declara la variable u1, la cual es una estructura tipo union. El
espacio de almacenamiento para la variable a es compartido por la variable b, en
consecuencia, al escribir sobre cualquiera de estas dos variables se altera el contenido de
ambas.

Ejemplo: union con nombre

union ux { short a; long b; } u1;

En el ejemplo anterior se declara la variable u1, la cual es una estructura tipo union. El
espacio de almacenamiento para la variable a es compartido por la variable b. Es decir, el
compilador reservará espacio en la memoria para la variable de mayor tamaño (que para
éste caso es b ). Ahora bién, suponiendo que en su equipo el tipo long ocupa 32 bits y que
el tipo short ocupa 16 bits, entonces la variable a ocupará solamente los 16 bits menos
significativos, miemtras que la variable b ocupará todo el espacio, o sea los 32 bits;
Observe que en la sintaxis se ha especificado el nombre ux, mismo que puede ser empleado
para declarar cualquier número de variables de la union. Por ejemplo, a continuación se
declaran las variables u2 y u3 del tipo union ux creado en el ejemplo anterior.

union ux u2, u3;

[editar] class: sintaxis


<classkey> <classname> [<:baselist>] { <member list> } [lista de
variables] ;

• <classkey> es una de las palabras "class", "struct", or "union".


• <baselist> lista de clas(es) base de donde se deriva esta clase.
<baselist> es opcional.
• <member list> declara los datos miembros y funciones miembros de la
clase.
• [lista de variables] esta entrada es opcional y se usa para instanciar
variables u objetos de esta clase.

Nota: Dentro de una clase,


• los datos son llamados "datos miembros"

• las funciones son llamadas "funciones miembros".

• El mecanismo para acceder a los miembros de una class es igual que


aquel utilizado para acceder a los miembros de una struct

Las clases son algo así como "super" estructuras capaces de agrupar no solo datos
miembros sino también funciones miembros. En el lenguaje común a los datos miembros
de una clase se les conoce como atributos; mientras que a las funciones miembros de una
clase se les llama métodos. Normalmente, los métodos se emplean para leer o escribir los
atributos. Es decir, la norma general es no permitir el acceso directo a los atributos de una
clase, con la idea de aumentar la seguridad de los datos.

En seguida se mostrará el código para crear la clase Pareja, misma que poseerá los atributos
a y b, y los métodos setA(), setB(); getA(), getB(), y mostrar();

class Pareja {
int a, b;
public:
void setA(int n) { a = n; }
void setB(int n) { b = n; )
int getA() { return a; }
int getB() { return b; }
void mostrar() {
cout << "a = " << a << "; b = " << b << endl;
}
} p1;

Nota: por omisión, los miembros de una clase son privados, lo cual significa que los
objetos instanciados de dicha clase no tendrán acceso a los mismos. Así, en el ejemplo
anterior se está creando la clase Pareja, y al mismo tiempo el objeto p1. Luego, para leer o
escribir los atributos de p1 se debe hacer a traves de los métodos definidos con tal objetivo.
Por ejemplo, con el siguiente fragmento de código se establecen respectivamente a 100 y a
200 los atributos a y b; y posteriormente se despliegan por medio del método mostrar().

p1.setA(100);
p1.setB(200);
p1.mostrar();

[editar] struct vs. class


Esta sección no pretende enseñar que el uso de la palabra struct es lo mismo que usar la
palabra class. Sin embargo, como ya se mencionó en una sección anterior a esta, las
estructuras (struct) pueden extenderse de otras y heredar todos los miembros de la
estructura base. Otro punto que se demostrará aqui es el hecho de que las estructuras en C+
+ (no en C estándar) pueden contener miembros funciones. Por supuesto, el compilador
trata a una struct de una forma diferente que a una class. Entre algunas de las diferencias
que se pueden mencionar respecto a las estructuras contra las clases son:

• Los miembros de una struct son públicos por default, mientras que los
miembros de una class son privados por default.
• Los parámetros-argumentos struct se pasan normalmente por copia, los
parámetros-argumentos class se pasan normalmente por referencia.

// Este programa ha sido probado en Dev-C++ y Borland C++

#include <iostream>

using namespace std;

// estructura tipo clase base


struct Par {

int a, b;

// constructor base
Par() { a = b = 0; }

// destructor base
~Par() { cout << "hecho..." << endl; }

void setA(int n) { a = n; }
void setB(int n) { b = n; }

void mostrar() {
cout << "a = " << a << ", b = " << b << "; suma = " << a+b <<
endl;
}
};

// estructura tipo clase hija


// ParHijo es una extensión de Par, y por lo tanto hereda los miembros de
Par
struct ParHijo : Par {

// constructor del hijo


ParHijo(int a, int b) {
this->a = a;
this->b = b;
}
};

// prueba
void test00() {
ParHijo p1(100, 200); // p1 es instancia de ParHijo
p1.mostrar(); // se envía mensaje al método mostrar() de p1
}

// funcion principal
int main()
{
test00();
cin.get();
return 0;
}

Programación en C++/Funciones
De Wikilibros, la colección de libros de texto de contenido libre.
< Programación en C++
Saltar a navegación, buscar
← Estructuras Streams →

Contenido
[ocultar]

• 1 Funciones
o 1.1 Definiendo una función
o 1.2 Parámetros
o 1.3 Llamar a una función
o 1.4 Funciones void
o 1.5 Funciones anidadas
o 1.6 Funciones de tipo puntero (*)
o 1.7 Variables estáticas y automáticas
o 1.8 Parámetros constantes
o 1.9 Parámetros con valor por defecto
o 1.10 Parámetros de tipo puntero
o 1.11 Parámetros estructurados
o 1.12 Funciones sobrecargadas

o 1.13 Número variable de parámetros

[editar] Funciones
[editar] Definiendo una función

Una función es un conjunto de líneas de código que realizan una tarea específica y puede
retornar un valor. Las funciones pueden tomar parámetros que modifiquen su
funcionamiento. Las funciones son utilizadas para descomponer grandes problemas en
tareas simples y para implementar operaciones que son comúnmente utilizadas durante un
programa y de esta manera reducir la cantidad de código. Cuando una función es invocada
se le pasa el control a la misma, una vez que esta finalizó con su tarea el control es devuelto
al punto desde el cual la función fue llamada.

<tipo> [clase::] <nombre> ( [Parámetros] )


{
cuerpo;
}

Ejemplo de una función

Para comenzar, vamos a considerar el caso en el cual se desea crear la función cuadrado(),
misma que deberá volver el cuadrado de un número real (de punto flotante), es decir,
cuadrado() aceptará números de punto flotante y regresará una respuesta como número
flotante.

Nota: aunque para la función que veremos el tipo de retorno coincide con el tipo de
parámetro pasado, algunas veces las cosas pueden cambiar, es decir, no es obligatorio que
una función reciba un parámetro de un tipo y que tenga que regresar una respuesta de dicho
tipo.

// regresar el cuadrado de un número


double cuadrado(double n)
{
return n*n;
}

[editar] Parámetros
Normalmente, las funciones operan sobre ciertos valores pasados a las mismas ya sea como
constantes literales o como variables, aunque se pueden definir funciones que no reciban
parámetros. Existen dos formas en C++ de pasar parámetros a una función; por referencia o
por valor. El hecho es que si en una declaración de función se declaran parámetros por
referencia, a los mismos no se les podrá pasar valores literales ya que las referencias
apuntan a objetos (variables o funciones) residentes en la memoria; por otro lado, si un
parámetro es declarado para ser pasado por valor, el mismo puede pasarse como una
constante literal o como una variable. Los parámetros pasados por referencia pueden ser
alterados por la función que los reciba, mientras que los parametros pasados por valor o
copía no pueden ser alterados por la función que los recibe, es decir, la función puede
manipular a su antojo al parámetro, pero ningún cambio hecho sobre este se reflejará en el
parámetro original.

Parametros por valor

La función cuadrado() (ver arriba) es un clásico ejemplo que muestra el paso de


parámetros por valor, en ese sentido la función cuadrado() recibe una copia del parámetro
n. En la misma función se puede observar que se realiza un calculo ( n*n ), sin embargo el
parámetro original no sufrirá cambio alguno, esto seguirá siendo cierto aún cuando dentro
de la función hubiera una instrucción parecida a n = n * n; o n*=n;.

Parametros por referencia

Para mostrar un ejemplo del paso de parámetros por referencia, vamos a retomar el caso de
la función cuadrado, salvo que en esta ocasión cambiaremos ligeramente la sintaxis para
definir la misma. Veamos:

// regresar el cuadrado de un número


double cuadrado2(double &n)
{
n *= n;
return n;
}

Al poner a prueba las funciones cuadrado() y cuadrado2() se podrá verificar que la primera
de estas no cambia el valor del parámetro original, mientras que la segunda sí lo hace.

[editar] Llamar a una función


para llamar a la función cuadrado() vista anteriormente, podemos emplear:
cout << cuadrado(25);
cout << cuadrado(X);
R = cuadrado(X); // guardar en R el cuadrado de X

[editar] Funciones void


Bajo ciertas circunstancias se deseará escribir funciones que no regresen valor alguno (esto
sería algo parecido a escribir procedures en Pascal) y para ello podemos declarar a la
función como void. La palabra reservada void es utilizada para declarar funciones sin valor
de retorno y también para indicar que una función específica no requiere de parámetros. Por
ejemplo, la función pausa() que se verá en seguida, no devolverá valor alguno y la misma
no requiere de parámetros.

// esta función requiere de la librería iostream


void pausa(void)
{
cout << "Por favor presione <Enter> HOLA...";
cin.get();
cin.ignore(255, '\n'); // rechazar caracteres introducidos antes de
<Enter>
}

Notas: se debe de aclarar que el uso de la palabra void dentro de los parentesis es opcional
al momento de declarar una función. Asi, la función pausa() podría haberse declarado como
void pausa(), y la misma puede invocarse como: pausa();.

[editar] Funciones anidadas


A diferencia de Pascal, el lenguaje C,C++ no permite anidar funciones, sin embargo,
dentro de una funcíon puede existir la llamada a una o más funciones declaradas
previamente.

[editar] Funciones de tipo puntero (*)


En muchas ocasiones se desea que ciertas funciones regresen una referencia o puntero hacia
un tipo ( sea éste estructurado o no) específico de dato en lugar de un valor específico. En
tales casos, la función se deberá declarar como para que regrese un puntero. Por ejemplo,
supongamos que deseamos crear una función para convertir un número entero en notación
decimal a una cadena de caracteres en forma de números binarios, luego, la función
mencionada podría escribirse para que reciba el número entero como parámetro y regrese
un puntero a una cadena de caracteres conteniendo la conversión. Para ser más puntuales,
vamos a escribir un programa en donde se verá la función binstr(), y cuyo objetivo será
precisamente convertir números decimales en cadenas binarias.

Nota: observe que en la sintaxis para declarar funciones tipo puntero se debe de poner el
símbolo * despues del tipo y antes del nombre de la función que se está declarando. Esto se
puede ver en el programa, ya que la función binstr se declara como: char *binstr(unsigned
int);
#include <iostream>
#include <string.h>

using namespace std;

// declaración de prototipo
char *binstr(unsigned int);

// punto de prueba
int main()
{
int n = 128;
cout << "decimal = " << n << ", binario = " << binstr(n) << endl;
cin.get();
}

// definición de función binstr()


// nota: esta funcion requiere de la librería estándar string
char *binstr(unsigned int n)
{
static char buffer[65];
int i = 0;

strcpy(buffer, "0");

if (n > 0) {
while (n > 0) {
buffer[i] = ( n & 1 ) + '0';
i++;
n >>= 1;
}
buffer[i] = '\0';
strrev(buffer);
} // fin (n > 0)
return buffer;
}

[editar] Variables estáticas y automáticas


Dentro de una función, las variables y/o constantes pueden ser declaradas como: auto (por
omisión) o como static. Si una variable dentro de una función es declarada como estática
significa que la misma retendrá su valor entre las llamadas a la función. Por otro lado, la
variables automáticas pierden su valor entre las llamadas. En el programa anterior puede
verse que el arreglo de caracteres (buffer[65]) se ha declarado como estático para garantizar
que dicho buffer retenga los datos aún despues de que la función termine. En el mismo
ejemplo, si el buffer no se declara como estático, el contenido del mismo podría ser
destruido al salir de la función y los resultados obtenidos podrían ser no deseados.

[editar] Parámetros constantes


Los parámetros usados por una función pueden declararse como constantes ( const ) al
momento de la declaración de la función. Un parámetro que ha sido declarado como
constante significa que la función no podrá cambiar el valor del mismo ( sin importar si
dicho parámetro se recibe por valor o por referencia ).

Ejemplo:

int funcionX( const int n );


void printstr( const char *str );

[editar] Parámetros con valor por defecto


Los parámetros usados por una función pueden declararse con un valor por defecto. Un
parámetro que ha sido declarado con valor por defecto es opcional a la hora de hacer la
llamada a la función. Ejemplo: Dada la función:

void saludo( char* mensaje = "Hola sudafrica 2010" );

la misma puede ser invocada como:

saludo(); // sin parámetro


saludo("Sea usted bienvenido a C++"); // con parámetro

Para ver un ejemplo más, vamos a considerar el caso de la función binstr() del programa
funciones01. Ahora, vamos modificar dicha función, salvo que esta ocasión nos interesa
que la misma sirva para convertir números decimales en cadenas numéricas y cuya base de
conversión sea pasada como parámetro. Es decir, la función de la que estamos hablando
podrá convertir números decimales a: binario, octal, decimal, hexadecimal, etc.; y la única
condición será que la base indicada esté entre el 2 y el 36, inclusive.

Nota: Ya que la función servirá para convertir números a cualquier representación la


nombraremos como numstr() en lugar de binstr(). Si la función es invocada sin el
parámetro base regresará una cadena de digitos decimales.

#include <iostream>
#include <stdlib.h>

using namespace std;

// declaración de prototipo
char *numstr(unsigned int, const int base = 10);

// punto de prueba
int main()
{
int n = 128;
cout << "decimal = " << n << ", binario = " << numstr(n, 2) << endl;
cout << "decimal = " << n << ", octal.. = " << numstr(n, 8) << endl;
cin.get();
}
// definición de función numstr()
// nota: esta funcion requiere de la librería stdlib.h
char *numstr(unsigned int n, const int base)
{
static char buffer[65];
itoa(n, buffer, base);
return buffer;
}

[editar] Parámetros de tipo puntero


Anteriormente se mencionó que en C++ los parámetros a una función pueden pasarse por
valor o por referencia, al respecto, podemos agregar que los parámetros también pueden
pasarse como punteros. El paso de parámetros de punteros es bastante parecido al paso de
parámetros por referencia, salvo que el proceso de los datos dentro de la función es
diferente. Por ejemplo, las funciones:

void referencia( int &X ) { X = 100; }


void puntero( int *X ) { *X = 100; }
ambas reciben un puntero o referencia a un objeto de tipo entero, por lo tanto cualquiera de
las funciones del ejemplo puede cambiar el valor de la variable entera apuntada por X, la
diferencia radica en la forma en que cada una de las mismas lleva cabo la tarea. Si en la
función puntero() en lugar de usar *X = 100; se usara X = 100; se le asignaría 100 al
puntero X, más no al objeto apuntado por X, y esto podría ser la causa de que el programa
se terminara de manera abrupta.

[editar] Parámetros estructurados


Al igual que cualquier otro tipo los parámetros de tipo estruturado pueden pasarse por valor
o por referencia, sin embargo, podría ser que si una estructura es pasada por valor el
compilador mostrara una advertencia ( warning ) indicando que se pasado por valor una
estructura, puesto que el paso de estructuras por valor es permitido usted puede ignorar la
advertencia, pero lo mejor es pasar estructuras por referencia. Si una estructura es pasada
por valor y si esta es muy grande podria ser que se agotara la memoria en el segmento de
pila ( Stack Segment ), aparte de que la llamada a la función sería más lenta.

Para ver un ejemplo, consideremos el caso del siguiente tipo estructurado:

struct empleado {
char nombre[32];
int edad;
char sexo; };

Ahora, pensemos que deseamos escribir una función para imprimir variables del tipo
empleado. Así, la función puede escribirse de las tres maneras siguientes:

void ImprimeEmpleadoV( empleado e)


{
cout << "Nombre: " << e.nombre << endl;
cout << "Edad: " << e.edad << endl;
cout << "Sexo: " << e.sexo << endl;

// Parametro empleado pasado por referencia


void ImprimeEmpleadoR( empleado &e )
{
cout << "Nombre: " << e.nombre << endl;
cout << "Edad: " << e.edad << endl;
cout << "Sexo: " << e.sexo << endl;

// Parametro empleado pasado como puntero


void ImprimeEmpleadoP( empleado *e )
{
cout << "Nombre: " << e->nombre << endl;
cout << "Edad: " << e->edad << endl;
cout << "Sexo: " << e->sexo << endl;
}

[editar] Funciones sobrecargadas


C++, a diferencia del C estándar, permite declarar funciones con el mismo nombre y a esto
se conoce como sobrecarga de funciones. Las funciones sobrecargadas pueden coincidir
en tipo, pero al menos uno de sus parámetros tiene que ser diferente. En todo caso, si usted
trata de declarar funciones sobrecargadas que coincidan en tipo y número de parámetros el
compilador no se lo permitirá. Para poner un ejemplo vamos a considerar el caso de dos
funciones cuyo nombre será divide, ambas regresarán el cociente de dos números, salvo
que una de ellas operará sobre números enteros y la otra lo hará sobre números reales ( de
punto flotante ).

Nota: cuando en los programas se hace una llamada a una función sobrecargada, el
compilador determina a cual de las funciones invocar en base al tipo y número de
parámetros pasados a la función.

#include <iostream.h>
#include <stdlib.h>

using namespace std;

// divide enteros
int divide(int a, int b)
{
cout << "división entera" << endl;
return ( (b != 0) ? a/b : 0);
}

// divide reales
double divide(double a, double b)
{
cout << "división real" << endl;
return ( (b != 0) ? a/b : 0);
}
// punto de prueba
int main()
{
cout << divide(10, 3) << endl;
cout << divide(10.0, 3.0) << endl;
cin.get();
}

[editar] Número variable de parámetros


En C,C++ se pueden crear funciones que operen sobre una lista variable de parámetros, es
decir, en donde el número de parámetros es indeterminado. En esta sección se mostrará un
ejemplo de la manera en que podemos crear funciones para manejar tales asuntos, y para
ello haremos uso de tres macros soportadas por C++:

1. va_list puntero de argumentos


2. va_start inicializar puntero de argumentos
3. va_end liberar puntero de argumentos

La sintaxis que usaremos para declarar funciones con lista de parámetros variables es:

1) tipo nombrefuncion(...)
2) tipo nombrefuncion(int num, ...)

donde:

1. tipo es el tipo regresado por la función


2. nombrefuncion es el nombre de la función
3. int num es el número de parámetros que la función procesará
4. ... esta notación se emplea para indicar que el número de parámetros es variable

Nota: observe que la primera forma de declaración es realmente variable el número de


parámetros a procesar y en estos casos se debe establecer el mecanismo para determinar
cuando se ha procesado el último de los argumentos, en el segundo tipo de declaración el
número total de parámetros a procesar es igual al valor del parámetro num.

En el siguiente programa, por ejemplo, se define una función ( printstr ) que despliega una
lista variable de cadenas de caracteres.

#include <iostream.h>
#include <stdarg.h>

// despliega una lista de cadenas, la ultima debe ser NULL


void printstr(...)
{
va_list ap;
char *arg;
va_start(ap, 0);
while ( (arg = va_arg(ap, char*) ) != NULL) {
cout << arg;
}
va_end(ap);
}

int main()
{
printstr("Hola, ", "Esta es\n", "una prueba\n", NULL);
cin.get();
return 0;
}

En el programa que se listará en seguida, se define la función suma(), misma que operará
sobre listas de números enteros, la función devolverá la suma de dichos números.

#include <iostream>
#include <stdarg.h>

using namespace std;

// Esta función opera sobre una lista variable de números enteros


int suma( int num, ... )
{
int total = 0;
va_list argptr;
va_start( argptr, num );

while( num > 0 ) {


total += va_arg( argptr, int );
num--;
}

va_end( argptr );
return( total );
}

int main()
{
cout << suma(4, 100, 200, 300, 400) << endl;
cin.get();
return 0;
}

También podría gustarte