Está en la página 1de 21

FUNDAMENTOS-DE-PROGRAMACION.

pdf

an0nymous

Fundamentos de Programación

2º Grado en Ingeniería de las Tecnologías de Telecomunicación

Escuela Técnica Superior de Ingenierías Informática y de


Telecomunicación
Universidad de Granada

Reservados todos los derechos.


No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
FUNDAMENTOS DE PROGRAMACIÓN

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Tema 1

Programa: Es el conjunto de instrucciones especificadas en un lenguaje de programación


concreto, que pueden ejecutarse en un ordenador y que resuelven un problema.

Lenguaje de programación: Lenguaje formal utilizado para comunicarnos con un ordenador e


imponerle la realización concreta de un conjunto de órdenes.

El lenguaje ensamblador se utiliza para programar drivers, microcontroladores, etc. Depende


del microprocesador.

Lenguaje de alto nivel. C, C++, Java

Reseña histórica

Reservados todos los derechos.


Algoritmo: secuencia ordenada de instrucciones que resuelve un problema concreto,
atendiendo a las siguientes características básicas:

- Corrección
- Precisión
- Repetitividad
- Finitud

Características esenciales

- Validez
- Eficiencia

Implementación de un algoritmo: Transcripción a un lenguaje de programación de un


algoritmo.

Código fuente: código escrito en un lenguaje concreto.

Una sentencia es una parte del código fuente que el compilador puede traducir en una
instrucción en código binario. Van separadas por ;

Sentencias (2 tipos):

- de declaración de datos. float dato1;


- de cálculo, a través de =. dato1=3;

Cuando la entrada es un fichero (y no el teclado), la lectura es automática sin que se espere la


tecla Intro. Es una asignación en tiempo de ejecución.

Componentes léxicos o tokens: es un carácter o grupo de caracteres alfanumérticos o


simbólicos que representa la unidad léxica mínima que el lenguaje entiende. Ejemplos: main ( ;
hip * por otra parte ni | ni ((* son tokens válidos.

Reglas sintácticas que dicen como han de determinarse los tokens.

Palabras reservadas. Son tokens formados por caracteres alfabéticos con un significado
específico. Ej: main

Flujo de control: especificar el orden en el que se han de ejecutar las sentencias. (if, while, for)

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Tipos de errores

- Errores en tiempo de compilación. Ocasionados por un fallo de sintaxis en el código


fuente. No se genera el programa ejecutable.
- Errores en tiempo de ejecución. Se ha generado el programa ejecutable, pero se
produce un error durante la ejecución.
- Errores lógicos. Se ha generado el programa ejecutable, pero el programa ofrece una
solución equivocada.

Un dato es un conjunto de celdas o posiciones de memoria que tiene asociado un nombre


(identificador) y un contenido (valor).

Tipos de datos

Literales: son la especificación de un valor concreto de un tipo de dato. Tenemos varios tipos:

- Literales numéricos: 2 3 3.5


- Literales de cadenas de caracteres: cero o más caracteres entre “”. Ej: “Hola”
- Otros tipos: literales de caracteres.

Variable local: si se declara después de main.

Variable global: si se declara antes de main. Su ámbito incluye todas las funciones definidos
después. Permite que las funciones se puedan comunicar a través de ellas y no de los
parámetros. Esto es pernicioso para la programación estructurada, fomentando la aparición de
efectos laterales. Ejemplo de acoplamiento externo.

Cada variable debe estar asociado a un único tipo de dato (el tipo no puede cambiarse durante
la ejecución). El valor que se le puede asignar a una variable depende del tipo de dato con el
que es declarado.

Cuando se declara una variable y no se inicializa, ésta no tiene ningún valor asignado por
defecto. Puesto que desconocemos su valor, lo podremos considerar como basura, y lo
representaremos gráficamente por ?.

Variables a las que solo le permitimos tomar un único valor, fijado de antemano. Es posible
con constantes

Suelen usarse identificadores sólo


con mayúsculas

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Datos: variables (datos que varían a lo largo del programa) y constantes (no varían).

Una expresión es una combinación de datos y operadores sintácticamente correcta, que el


compilador evalúa y devuelve un valor. Deben aparecer a la derecha de una asignación.

Comportamiento de un tipo de dato:

- El rango de valores que puede representar, que depende de la cantidad de memoria


que dedique el compilador a su representación interna. Intuitivamente, cuanta más
memoria se dedique para un tipo de dato, mayor será el número de valores que
podremos representar.
La cantidad de memoria que el compilador asigna a cada tipo se puede consultar
mediante el operador sizeof() cuyo resultado es un entero que contiene el número de
bytes asignados a .
- Conjunto de operadores que pueden aplicarse a los datos de ese tipo.

Lo usual es que un int ocupe la longitud de la palabra del segmento de datos del sistema
operativo. Hoy en día, lo usual es 32 bits (4 bytes) y 64 bits (8 bytes).

¿Qué tipo de dato se usa para representar un literal entero? Depende de la memoria
reservada y los tipos disponibles por cada compilador

++ y –

Incrementan y decrementan,
respectivamente, el valor de la variable
entera sobre la que se aplican (no pueden
aplicarse sobre una expresión).

En el ejemplo no entra porque ++ está


después

Si el ++ está después de la variable,


primero evalúa la condición y después
incrementa, si está delante de la variable,
primero incrementa y luego evalúa.

Reglas de precedencia

Representación en coma fija. Parte entera, parte real

Forma de representar números reales: coma flotante. En esta representación la parte entera
se expresa en binario y la parte real se representa usando potencias inversas de 2. Usando este
método NO es posible representar de forma exacta muchos reales. La regla a usar es que, con
32 bits, se consigue una precisión aproximada de 7 dígitos y con 64 bits, se consiguen
aproximadamente 16 dígitos para la parte entera

Los tipos enteros representan datos enteros de forma exacta. B Los tipos reales representan la
parte entera de forma exacta, siempre que trabajemos con menos de 16 dígitos (en una

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
representación con 64 bits) La parte real será sólo aproximada. Además, la aproximación será
mejor cuanto menor sea la parte entera del número.

¿Qué pasa cuando asignamos un real a un entero? Simplemente, se pierde la parte decimal, es
decir, se trunca

El casting a entero de un float que contenga infinito o indeterminación es un valor basura.

Desbordamiento-> Error lógico, almacena basura

Literales de carácter

- Carácter encerrad en comillas


simples: ‘S’
- Secuencia de escape \n \t

Ctype: tolower(‘A’) ->a

Toupper(‘a’)->A

Tipo char: tipo entero pequeño

Cadena de caracteres “Hola”, “a”

Trabajar datos tipo char: vectores de caracteres o punteros

Booleano: 0 (false), distinto de 0 (true)

Isalpha: función que devuelve true (1) si todos los caracteres de un string son alfabetos.

Isdigit: función que devuelve true (1) si el carácter es un número.

Isalnum: función que devuelve true (1) si el carácter es alfanumérico, es decir si isalpha e
isdigit también devuelven true. Erguj8t4t34t

Reglas de precedencia

tipo enumerado. Es un tipo


entero que sólo acepta unos
valores concretos especificados
por el programador. Se le puede
asignar un número muy limitado
de valores. Si no se pone ningún
valor en la definición del tipo, C
le asigna a cada valor del
enumerado el siguiente entero
del asignado al valor anterior. Al
primero le asigna el cero. Pg81.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Tema 2. Estructuras de control

Estructura Secuencial: las instrucciones se van ejecutando sucesivamente, siguiendo el orden


de aparición de éstas. No hay saltos.

Una estructura condicional es una estructura que permite una ejecución condicional. Existen
tres tipos: Simple, Doble y Múltiple. Una ejecución condicional consiste en la ejecución de una

Reservados todos los derechos.


(o más) sentencia(s) dependiendo de la evaluación de una condición.

Estructura condicional simple.

Si hay varias sentencias, es necesario encerrarlas entre llaves. Dicho de otra forma: si no
ponemos llaves, el compilador entiende que la única sentencia del bloque if es la que hay justo
debajo.

Estructura condicional doble.

Anidamiento de estructuras condicionales. Dentro de un bloque if (else), puede incluirse otra


estructura condicional, anidándose tanto como permita el compilador. Al aumentar el
anidamiento se va perdiendo en legibilidad y concisión.

Álgebra de Boole

Leyes de Morgan

Tipo bool como tipo entero. En C, no hay el tipo lógico booleano se hace con un tipo entero.
Cualquier expresión entera que devuelva el cero, se interpretará como false. Si devuelve
cualquier valor distinto de cero, se interpretará como true.

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Siempre es true

asigna a a el valor 0 y como es false se


ejecuta el else, si no fuese 0
se ejecutaría siempre el if.

Primero asigna y luego


evalua.

Evaluación ciclo corto y largo

if ( (a>0) && (b(<0) && (c<1) ) si a = -3, n ciclo largo se evaluará toda la expresión y en ciclo
corto sólo la primera, sabiendo ya que es false. La mayoría de compiladores usan ciclo corto.

Por lo tanto, pondremos primero aquellas condiciones que sean más probables de evaluarse
como false Nota. La misma idea pasa cuando el operador es || pero se ponen primero aquellas
condiciones que sean más probable evaluarse como true.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
La expresión 1.0 == (1.0/3.0)*3.0 podría evaluarse a false
debido a la precisión finita para calcular (1.0/3.0)
(0.333333333).

Estructura condicional múltiple if / else if / else if / else

Switch

Break;

Estructura repetitiva (bucles, ciclos, lazos)

Permite la ejecución de una secuencia de sentencias: o


bien, hasta que se satisface una determinada condición
(controladas por condición) o bien, un número
determinado de veces (controladas por contador)

Pre-test

Post-tes

Escribe uno más. While

lectura anticipada. Leemos el primer valor con scanf antes de entrar al bucle y comprobamos si
hay que procesarlo (el primer valor podría ser ya el
terminador!)

Bucles sin fin

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Bucles for. Se utilizan para repetir un conjunto de sentencias un número de veces fijado de
antemano. Se necesita una variable contadora, un valor inicial, un valor final y un incremento.

Cuando termina un bucle for, la variable contadora se queda con el primer valor que hace que
la condición del bucle sea falsa

Iteraciones en un for Si incremento = 1, Vinic es menor que Vfinal y la condición es v_c <=
Vfinal

Vfinal - Vinic + 1
- Si incremento = 1, Vinic es menor que Vfinal y la condición es v_c < Vfinal
Vfinal – Vinic

Iteraciones e intervalos

Únicamente mirando la cabecera de un bucle for sabemos cuantas iteraciones se van a


producir. Por eso, en los casos en los que sepamos de antemano cuantas iteraciones
necesitamos, usaremos un bucle for. En otro caso, usaremos un bucle while ó do while.

No se debe modificar el valor de la variable controladora, ni el valor final dentro del cuerpo del
bucle.

¿Puede usarse entonces, cualquier condición dentro de la cabecera del for? Sí, pero no es muy
recomendable.

¿podemos suprimir algunas expresiones de la cabecera de un bucle for? La respuesta es que sí,
pero hay que evitarlas SIEMPRE. Oscurecen el código. Pg 97 tema 2

¿Cuando usar un ciclo for?

- En los ciclos controlados por contador


- Cuando el flujo de control del ciclo tenga SIEMPRE:
– Una sentencia de inicialización del contador
– Una condición de continuación que involucre al contador
– Una sentencia de actualización que involucre al contador

Anidamiento bucles. No hay límite. Deben estar inscritos unos dentro de otros.

Otras estructuras de control: goto / continue / break / exit (no usar, excepto break)

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Tema 3

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Funciones. Objetivo: descomponer la
resolución de un problema en tareas
menos complejas. Cada tarea será
resuelta por un algoritmo, y éste
vendrá encapsulado en una función.

Los parámetros formales son aquellos especificados en la cabecera de la función. Hay que
especificar su tipo de dato. Sólo se conocen dentro de la función.

Los parámetros actuales son las


expresiones pasadas como
argumentos en la llamada a una

Reservados todos los derechos.


función.

Flujo de control. Cuando se llama a la función, el parámetro formal recibe la asignación del
parámetro actual. Esto es Paso por valor. Cuando se ejecuta toda la función devuelve return
<expresión> al sitio en el que fue la llamada. La llamada a una función es una expresión.

Correspondencia entre parámetros actuales y formales. Debe haber el mismo número de


ambos. Y el parámetro actual debe tener un valor correcto (error lógico) y deben ser del
mismo tipo.

Problema: que el tipo del parámetro formal sea más


pequeño que el actual. El formal se puede quedar con
basura.

Entradas y salidas de una función. Viendo la cabecera de


una función, sabemos qué hace y qué necesita para hacerlo. No nos importa cómo lo hace.

Ventajas uso de funciones:

- Reutilización
- Código menos propenso a errores
- Actualización
- Abstracción

Ámbito de un dato. Datos locales: solo se conocen dentro de la función.

Scope o ámbito de un dato v es el conjunto de todas las funciones que pueden referenciar a v.

Pila. Entorno que se crea en una zona de memoria específica cada vez que se llama a una
función. Las modificaciones en el parámetro formal no afectan al actual (si lo hiciese: paso por
referencia)

Funciones mal codificadas: tema 3, pg 31

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Funciones void. Resuelve la tarea de realizar la presentación del programa por pantalla, pero
no calcula (devuelve) ningún valor. Su llamada constituye una sentencia, no una expresión. No
hay sentencia return.

Paso de parámetros por referencia.

Las variables coc y res son modificadas por


las sentencias, y las varibles horas y minutos
se quedan con ?. Deberiamos pasar coc y res
por referencia.

Paso por referencia. (*) El parámemtro


formal está ligado al actual. Cuando dentro
de la función modifiquemos el parámetro
formal pasado por referencia, también se
modificará el parámetro actual.

Las constantes, literales y expresiones no pueden ser parámetros actuales pasados por
referencia. Deben pasarse por valor. Pasamos por referencia los datos que vamos a modificar.
Pero obviamente, si tienen algún valor previamente establecido, podemos acceder a él.

Resumen:

- Los parámetros por valor son datos que necesita conocer una función (son entradas).
- Los para. por referencia corresponden a datos modificados por la función, son salidas.
También pueden ser datos de entrada o salida si la función utiliza ese parámetro.

Cohesión: medida del grado de identificación de una función


con una tarea concreta. Cuanto más específica sea la tarea de
una función, mayor será su cohesión. Medida de la relación
de los elementos dentro de una función.

Acoplamiento: medida del grado de interacción o


dependencia entre las funciones de un programa. Si una función llama a 10 funciones, tendrá
mayor acoplamiento que si llama a 2. medida de la relación que hay entre las funciones.

Una función de cálculo nunca debe imprimir mensajes. Se hace en la función que la llama.

¡! Una función void puede incluir una sentencia return; (sin expresión), para salir de la
ejecución de la función en ese momento.

Orden construir funciones (pg 102, 3). Diseño descendente / modular (pg 112) / Integración
ascendente

Funciones recursivas. Hacer que una función en el cuerpo


de la función llame a la misma función.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Tema 4

Un tipo de dato compuesto es una composición de tipos de datos simples (o incluso


compuestos) caracterizado por la organización de sus datos y por las operaciones que se
definen sobre él. Un vector es un tipo de dato, compuesto de un número fijo de componentes
del mismo tipo y donde cada una de ellas es
directamente accesible mediante un índice. No
puede dimensionarse con una variable.

El índice de la primera componente del vector es 0, el índice de la última componente es


n.componentes-1. Cada componente es una variable más. No se permiten asignaciones
globales, las asignaciones se realizan componente a
componente.

Leer vector: leer útil del vector antes de llamar a la función void. Se utilizará un bucle.

Útil: Número de componentes usadas. Resto son 0. Índices componentes usadas (0, útil-1)

Inicializar vector 

Las componentes de un vector son


variables cualesquiera por lo que las
podemos pasar como parámetro actual a
cualquier función. También se puede pasar
por referencia una componente.

El compilador trata a un vector como un dato


constante que almacena la dirección de memoria
donde empiezan a almacenarse las componentes.

¿Podemos pasar de golpe todas las componentes a


una función? NO puede pasarse una copia de golpe,
de todas las componentes del vector. Pero sí podemos pasar una copia de la dirección de
memoria que contiene el vector (0010002 en el ejemplo). Para indicarlo, se pone [] en el
parámetro formal. En C, pasar un vector como parámetro significa pasar la dirección de
memoria de la primera componente del vector. A partir de ella, se accede al resto de
componentes y podrá modificarlas.

Usualmente, además de pasar el vector a una función, también le pasaremos el número de


componentes utilizadas (pero no la dimensión). Si no se indica lo contrario, JAMÁS
modificaremos las componentes de un vector de entrada. Usar el calificador const en aquellos
casos en los que la función no necesita modificar las componentes del vector.

Algoritmos de búsqueda. Secuencial y binaria.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Búsqueda secuencial: (precondición: útil de v de estar en el rango correcto)

- el vector no se supone ordenado


- Como no se modifica se pasa como const <tipo> v[]
- Si no se encuentra se devuelve un valor imposible de posición (-1)

Búsqueda binaria: (precondición: se aplica sobre un vector ordenado)

Una función no puede devolver un vector

Algoritmos de ordenación (interna y externa):

Ordenación interna: Todos los datos están en memoria principal durante el proceso de
ordenación. (Inserción / Selección / Intercambio directo o burbuja)

Ordenación externa: Parte de los datos a ordenar están en memoria externa mientras que otra
parte está en memoria principal siendo ordenada

Ordenación por selección: En cada iteración, se selecciona la componente más pequeña del
sub-vector derecha y se coloca al final del sub-vector izquierdo.

Ordenación por inserción Idea: El vector se divide en dos subvectores: el de la izquierda


ordenado, y el de la derecha desordenado. Se coge el primer elemento del subvector
desordenado y se inserta de forma ordenada en el subvector ordenado. ¿Útil+1 referencia?

Ordenación por intercambio directo (burbuja): Al igual que antes, a la izquierda se va dejando
un subvector ordenado. Desde el final y hacia atrás, se van comparando elementos dos a dos y
se deja a la izquierda el más pequeño (hay que intercambiarlos).

Cadenas de caracteres

Una cadena de caracteres es una secuencia ordenada de caracteres de longitud variable.


Podemos representarlo de dos maneras:

Char* Vector de char

Para delimitar el final del vector se usa un carácter especial ’\0’


que se le asignara a la última componente utilizada. ’\0’ se conoce
como carácter nulo o marca de fin de cadena. Tamaño será nº de caracteres a almacenar +1.
La asignación se hace componente a componente, sólo se hace en la inicialización.

Al declarar un string, podemos darle un valor inicial como cualquier otro vector

Biblioteca string:

- strcpy: copia la cadena


- strlen: longitud de cadena
- strcat: concatena las cadenas (s1 y s2) y el resultado se guarda en s1
- strcmp: compara las cadenas (s1 y s2). Si s1<s2 devuelve un número <0, si s1=s2
devuelve 0 y en otro caso devuelve n>0.

con un vector de char sí podemos usar printf, con uno noma, no.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Lectura char con scanf: Si la cadena que se desea introducir contiene, la variable contendrá los

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
caracteres hasta el primer separador. Se soluciona con fgets.

Comportamiento scanf (“%d”, %entero): Si el dato no corresponde a un entero, se lee un valor


basura.

Comportamiento scanf (“%c”, %caracter): pg 109, 4

Carácter nulo: Para indicar el final de la cadena hemos


usado el carácter ’\0’. En C, este literal es el mismo que
el literal 0, por lo que los recorridos con cadenas
también pueden hacerse usando 0.

MATRICES

Declaración

Reservados todos los derechos.


Cada componente <Ident>[<i>] [<j>] es una variable
más del programa.

En la declaración de la matriz se pueden asignar


valores a toda la matriz. Posteriormente, no es
posible: es necesario acceder a cada componente
independientemente.

Representación en memoria matrices:

Todas las posiciones de una matriz están realmente contiguas en memoria. Sea m una matriz,
m contiene la dirección de memoria de la primera componente. Para saber dónde está m[i][j],
el compilador necesita saber cuánto vale DIM_COL_m, pero no DIM_FIL_m.

Al pasar una matriz como parámetro, debemos incluir la constante de dimensión de las
columnas. Además, esta ha de ser un define o un literal y se copiará la dirección de memoria
que contiene la matriz pasada como parámetro actual.

¿Cuantas componentes utilizadas tiene el vector m[i]? util_Col_m

Para una matriz n-dimensional hay que especificar todas


las dimensiones excepto la primera.

TEMA 5

Los vectores almacenan de forma compacta información del mismo tipo sobre una misma
entidad. Los registros (struct) almacenan de forma compacta información de distinto tipo
sobre una misma entidad.

El tipo struct puede definirse:

- Dentro de una función. Sólo puede ser usado dentro de la función (poco usual)

- Al principio del fichero. Será accesible por todas las funciones definidas con posterioridad

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Las variables de tipo struct pueden definirse en los mismos
sitios que cualquier otra variable.

Campos: NIF, Nombre, EsBecario…

Variable: un_alumno

<nombre_variable>.<nombre_campo> es una variable del


tipo declarado. Ej: un_alumno.Edad = 17;

Un campo de un struct puede ser un vector. Ej: NIF

Se pueden construir vectores de struct.

Un campo de un struct puede ser otro struct.

A un vector no se le puede asignar otro vector, a un struct sí se le puede asignar otro struct,
copiándose todos los valores de todos los campos. Curiosamente, si el struct contiene un
vector, se asignan todas las componentes una a una (recordad que los vectores, tal cual, no
podían asignarse entre sí).

Es posible pasar un struct completo como parámetro a una función, puede hacerse por valor o
por referencia.

- Paso por valor struct: se realiza una copia del parámetro actual en el parámetro formal
La modificación del parámetro formal no altera el actual, igual que con los campos.
Duplica la memoria en pilasol: paso por referencia constante

Una función también puede devolver un struct. Declaramos una variable local tipo struct y al
final ejecutamos un return.

- Paso por referencia. El parámetro formal va ligado al actual. Si pasamos por referencia
un struct, las modificaciones de los campos del formal, serán modificaciones de los
campos del actual.
- Paso por referencia constante. Se puede modificar el puntero, pero no el objeto al que
apunta.

Si vamos a crear una función que acceda a las componentes del struct, pasaremos todo el
struct y no las componentes individualmente.

Tema 6

Un dato de tipo puntero contiene una dirección de


memoria. Una variable puntera SIEMPRE ocupa lo
mismo: 32 bits

Declaración 

Operador de dirección. &, devuelve la posición de memoria en la que empieza a almacenarse


la variable.

Ordenador de indirección.*puntero. Para acceder a la variable apuntada por un puntero

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Al evaluar *ptr, el compilador accede a tantos bytes como indique <tipo base>, a partir de la
dirección de memoria contenida en ptr.

Como * es una variable corriente, podemos hacerle lo que queramos, como por ejemplo
pasarla por valor o por referencia.

 Modifica *ptr cuando ptr todavía no tiene asignada


una dirección de memoria correcta.

Imprimiría basura

Todo sigue igual cuando el puntero contiene la dirección de memoria de un struct.

Asignaciones y comparación entre punteros

Al asignar un puntero a otro, se asigna su contenido, es decir, la dirección de memoria que


contiene. Deben ser del mismo tipo base, si no  error de compilación

Operador flecha. (->) Obtiene el campo de una struct apuntada por un puntero

Asignación entre dos structs copia campo a campo, por tanto, si el campo es un puntero se
copiará la dirección de memoria que contiene.

Puntero NULL (0): es un valor de un puntero (dirección de memoria) especial sobre el que
tenemos la certeza de que no es la dirección reservada para ninguna variable.

Cuando pasamos un puntero por valor, estamos pasando una copia del contenido del puntero
(dir. memoria)

¡Cuidado!: Al pasar un puntero como parámetro


podemos modificar la variable apuntada por él.

Para esto podemos usar cont, y así evitar modificar


por accidente la variable apuntada. Si hiciésemos
esto en el ejemplo nos daría error de compilación.

Las modificaciones del puntero que hagamos dentro de una función (el parámetro formal), no
afectan al puntero pasado como parámetro actual (como cualquier otro paso por valor
puntero)

Paso por referencia puntero: Además de poder modificar la variable apuntada por el puntero
(como en el paso por valor), también podemos modificar el puntero que pasen como
parámetro actual.

Asignación entre un puntero y un vector fijo

Los vectores clásicos (fijos) se comportan como


punteros constantes a posiciones contiguas
almacenadas en la pila.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Podemos pasar un vector fijo cómo parámetro a un puntero y pasar como parámetro actual un
puntero cualquiera no constante.

Si v es un parámetro formal (no es constante), podremos pasar un puntero como parámetro a


un vector fijo.

Objetivo: Crear variables (reserva de memoria) durante la ejecución (dinámica). Librerías


stdlib.h o alloc.h.

- Se reserva memoria con el operador malloc.


- Se libera memoria con el operador free.

La reserva dinámica de memoria con malloc, NO se realiza en la pila sino en otra zona llamada
Heap.

Si ejecutamos dos malloc sobre el mismo


puntero, la variable del heap creada en
primer lugar, permanece inaccesible,
consumiendo recursos.

Todas las variables locales a una función se almacenan en la pila y se pierden al terminar la
función. Esto también ocurre con un puntero local. La memoria que reservemos al ejecutar
malloc sobre un puntero, permanece en el Heap cuando termine de ejecutarse la función

Una función puede devolver un puntero.

Para evitar la notacion complicada float **p se puede usar typedef.

Vectores dinámicos. Un vector dinámico es un puntero. Dicho puntero apuntará a una


posición de memoria del Heap, a partir de la cual habrá varias variables contiguas. Las
componentes de un vector dinámico están en el Heap.

Para crear un vector dinámico tendremos que usar malloc e indicar el nº de componentes. Una
vez usadas las posiciones se destruyen con free.

Al hacer malloc, el SO devuelve la dirección inicial dónde se ha reservado memoria. Y el SO


sabe cuántos bytes hay reservados de dicha dirección inicial. Puede hacerse free con otro
puntero distinto al que se le hizo el malloc.

Siempre que necesitemos un vector local con un nº variable de componentes, usaremos un


vector dinámico

¿Cómo se pasa como parámetro un vector dinámico? Basta con pasar el puntero a la primera
posición. Es lo mismo que ocurría con los vectores fijos.

Para construir un vector dinámico dentro de una función, hacemos el malloc dentro de la
función y devolvemos la dirección de memoria devuelta por malloc

Intentad construir funciones que eviten hacer copias locales de vectores, ya que pueden ser
muy grandes y desbordarse la memoria.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
Estructura de datos para designar un tipo definido por nosotros, que nos permita representar

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
(almacenar) y manejar (operar) información relativa a una entidad.

Listas enlazadas. Crear una estructura de datos que me permita ir reservando dinámicamente
componentes, aumentando o disminuyendo el número de estas, de una forma eficiente.

- Es legal declarar un puntero al tipo TipoNodo, dentro de la definición del propio


TipoNodo.
- Debo guardar la dirección del primer nodo en un puntero llamado, por ejemplo, inicio.
- A partir del puntero inicio se irán accediendo al resto de los nodos.
- A partir de un nodo, accedemos al siguiente a través del campo next. Al revés no es
posible, ya que no almacenamos ningún campo anterior.
- Los nodos se alojan en el heap y NO ocupan posiciones contiguas en memoria.
- El conjunto de todos los nodos es lo que denominaremos una lista enlazada.
- En el campo next del último nodo, almacenamos el puntero nulo (0) NULL para indicar

Reservados todos los derechos.


que es el final de la lista.

Para añadir un nodo, debemos crearlo y engancharlo con el nodo anterior. Para ello, es
necesario modificar el campo next del último nodo.

El puntero inicio solo se modifica cuando se crea el primer nodo. La creación del resto de los
nodos dentro del bucle, no cambia el valor del puntero inicio.

Recorrido de una lista. Una vez creada una lista enlazada, la recorreremos con un puntero
(actual) que vaya apuntando a los distintos nodos, hasta llegar al último (NULL).

- Inicializaremos actual = inicio para procesar el primer nodo


- Con un bucle, iremos moviendo el puntero por los nodos de la lista ejecutando la
instrucción: actual = actual->next;
- Cuando actual sea igual a NULL, habremos terminado.

Si una función necesita acceder a los nodos de una lista enlazada, usualmente le pasaremos un
puntero al primer nodo (inicio).

Si una función necesita determinar que nodo cumple una propiedad determinada, devolverá
un puntero a dicho nodo.

Borrar todos los nodos de una lista

¿Puedo empezar a borrar desde el último hacia atrás? No, ya que el problema es que un nodo
no guarda como información la dirección del nodo anterior.

¿Qué hacemos entonces para liberar una lista? Antes de borrar el nodo actual debemos
guardar la dirección del siguiente nodo en un puntero auxiliar.

Lista doblemente enlazada: lista donde en cada nodo tenemos un enlace al nodo siguiente y
otro al anterior.

Añadir nodo a una lista enlazada: recorremos la lista para buscar el final y añadir ahí. Usamos
un puntero último apuntando al último nodo y así añadir sin tener que recorrer la lista.
Siempre consideramos primero si es viable añadir por el principio, pues es más fácil.

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
EXAMEN FP 2020 SOLUCIONES

1. Sobre la cohesión de una función: cuantas menos tareas haga una función mayor será
la cohesión (b)
2. Si hacemos int v[3]={1,2}  v[0]=1, v[1]=2, v[3]=0 (b)
3.

4. Sobre los struct se pasan por referencia o por valor según decida el programador
5. ¿Qué almacena una variable tipo puntero? Todas son correctas (a)
o La dirección de memoria donde hay un dato
o La dirección de memoria donde comienza a almacenarse una variable
o Un número entero habitualmente de 32 o 64 bits que representa una
dirección de memoria.
6. En qué condiciones el tamaño en bits que ocupa un entero será mayor que el tamaño
en bits que ocupa un float. Nunca, el tamaño que ocupa un entero puede ser mayor
que el que ocupa un float. (d)
7.

8. Sobre el acoplamiento de una función: es una medida del grado de interacción o


dependencia entre las funciones de un programa. (d)
9. Que hace el modificador const sobre un argumento de una función que es un puntero:
hace que lo que apunta el puntero no se pueda modificar (a)
10. ¿Qué es una lista doblemente enlazada? Una lista donde en cada nodo tenemos un
enlace al nodo siguiente y otro al anterior. (d)

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963
11. Si el ++ está después de la
variable, primero evalúa la
condición y después
incrementa, si está delante
de la variable, primero
incrementa y luego evalúa.
12. ¿Cómo podemos calcular lo
que hay que sumar a un
carácter en mayúsculas para
obtener el correspondiente
carácter en minúsculas?
Distancia = ’z’-’Z’ (a)
13. Sobre las variables globales: son la principal fuente de efectos colaterales en un
programa. (d)
14. Cuando leemos un vector de entrada debemos: leer el útil del vector en el programa
principal y las componentes del vector en una función. (a)
15. En el paso por referencia ninguna de las respuestas es correcta (c) Las constantes,
literales y expresiones no pueden ser parámetros actuales pasados por referencia.
Deben pasarse por valor. El parámetro actual NO se copia sobre el parámetro formal.
16. (d) Hay un ; después del for
17. El operador ->: obtiene el campo de una struct apuntada por un puntero. (a)
18. Infinitas iteraciones. Ninguna de las anteriores es correcta (d)
19. (b)
20. (d)Todas son correctas. Añadir nodo a una lista enlazada: recorremos la lista para
buscar el final y añadir ahí. Usamos un puntero último apuntando al último nodo y así
añadir sin tener que recorrer la lista. Siempre consideramos primero si es viable añadir
por el principio, pues es más fácil.
21. sobre el anidamiento con estructuras condicionales: se puede anidar cuantas veces se
desee (a)
22. (c)
23. Sobre el paso por referencia: si modificamos el parámetro formal se modifica el
parámetro actual (b)
24. ¿Cómo pasaríamos un vector por valor a una función? De ninguna forma, los vectores
no se pueden pasar por valor.
25.

Primero asigna,
después evalúa.

Reservados todos los derechos. No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-3752963

También podría gustarte