Bienvenidos a un nuevo curso. Ahora estoy en el ciclo de grado superior: Desarrollo de aplicaciones multiplataforma. Y voy a ser parte del experimento de la formación dual. Estaré haciendo practicas durante un año, y a la vez finalizando la formación.

Deseadme suerte.

Mostrando entradas con la etiqueta lenguaje C. Mostrar todas las entradas
Mostrando entradas con la etiqueta lenguaje C. Mostrar todas las entradas

viernes, 16 de enero de 2015

miércoles, 14 de enero de 2015

Estructuras de datos dinámicas

0

Tema 8b > particularizado para el caso de C

Estructura de datos
Una estructura de datos es una colección de datos organizados de una determinada manera.
Ejemplo: entero, real, vector (de...), registro, matriz, fichero (de...), ..., lista, cola, árbol...
Si tengo que trabajar con varios datos iguales en memoria, a veces un vector se queda demasiado grande, o demasiado pequeño. Si yo tengo un fichero de datos y quiero pasarlo a memoria para trabajar con él, si uso un vector, me puede ocurrir que sea insuficiente en cuanto a tamaño, o que esté desperdiciando la mayor parte de él.

Tipos de estructuras de datos
ED estáticas
- Una vez definidas no pueden variar.
- El contenido puede variar, pero no la estructura.
- Tamaño fijo, ya sea mediante...
     * Variables estáticas (tamaño fijado en compilación).
     * Variables dinámicas (tamaño fijado en ejecución).
ED dinámicas
- Podemos cambiar la estructura en cualquier momento.
- Tamaño aumenta o disminuye según se va ejecutando el programa y varían las necesidades.

¿Estructuras estáticas?
Inconvenientes de las estructuras estáticas (como un vector):
- Tamaño no puede aumentar ni disminuir. Hay que predecir el tamaño necesario.
- Reorganizar la lista de elementos implica mover muchos elementos. Es costoso.
Si tenemos una lista de elementos ordenados y queremos insertar uno nuevo manteniendo el orden:
- Con un vector:
     * Primero tenemos que disponer de espacio para el nuevo elemento (y puede ser que no tengamos).
     * Segundo tenemos que desplazar todos los elementos que están después de él en el orden para mantenerlo.
- con una EDD:
     * Siempre podemos insertar un nuevo elemento (salvo limitación de recursos).
     * Podemos insertar en cualquier posición, con coste bajo.

Tipos de EDD
Lineales: que aumentan su tamaño en una única dimensión:
- Listas
- Pilas
- Colas
No lineales: Que aumentan su tamaño en varias dimensiones:
- Árboles
- Grafos

Uso de las EDD
Las EDD no están directamente soportadas por el lenguaje. Tenemos que programarlas nosotros:
- Definir las estructuras de datos necesarias.
- Implementar las funciones y procedimientos que realicen las operaciones sobre las estructuras de datos que hemos definido.

El tipo de datos Lista
Concepto: Secuencia finita de cero o más elementos de un tipo determinado.
a1, a2, ..., an     n>=0
Cada a¡ es del tipo de los elementos de la lista.
n: longitud de la lista
- Si n=0: lista vacía.
- Si n>=1:a1 es el primer elemento y an es el último elemento.
Dado un elemento a¡, decimos que a¡ precede o es predecesor de a¡+1 y que a¡ sucede o es el sucesor de a¡-1.

Operaciones sobre una lista
Inicializar
Insertar (al principio, al final, o en una determinada posición)
Eliminar
Recorrer la lista
Tamaño
Recuperar (información de una posición concreta)
Localizar (posición a partir de información)
Copiar (una lista en otra)
...

Implementación del tipo de datos Lista
La lista nos la implementamos nosotros, así que lo hacemos como queremos de acuerdo con nuestras necesidades.
Una opción posible es implementarla como una lista enlazada.

Lista enlazada
Cada elemento de la lista se almacena en un nodo, que es una estructura.
Los nodos se identifican por su posición, que es una dirección de memoria, a la que algo apuntará.
Los nodos contienen un elemento de la lista y la posición al siguiente nodo.
El nodo que contiene el último elemento de la lista tiene NULL en el campo "SIGUIENTE NODO".
La lista es un puntero al primer elemento.

Definición de la lista
struct info {
.../* Rellenar con toda la información que deba contener un elemento de la lista */
}
struct nodo {
     struct info elemento;
     struct nodo *siguiente;
}
struct nodo *lista;

Inicializar lista
list=NULL;

Insertar al principio
Void insertarPrincipio (struct nodo **L, struct info *X){
     struct nodo *tmp;
     tmp=(struct nodo *) malloc (sizeof(struct nodo));
     tmp->elemnto=*X;
     tmp->siguiente=*L;
     *L=tmp;
}

Yo no he trabajado con punteros (solo copiado la teoría) y si no entiendes punteros, no alcanzas esto, esta dando una larga explicación... y yo me estoy quedando igual. Habrá que insistir en un futuro... No temo volver a preguntar cuando este preparada.
Es obligado hacer dibujo!

Deberes: ¿Como harías para insertar un elemento al final de la lista? ¿Como añadir a una posición cualquiera?


lunes, 12 de enero de 2015

Continuación de punteros

0

Punteros y matrices
Es la misma idea que cuando hemos hablado de vectores y punteros.
Una matriz es un puntero al primer elemento más una reserva de espacio para todos los elementos.
¿Cómo se almacenara una matriz en C? Por filas. El orden de los elementos en memoria es el siguiente (suponiendo 3x3):
m[filas][columnas]
m[0][0]
m[0][1]
m[0][2]
m[1][0]
m[1][1]
m[1][2]
m[2][0]
m[2][1]
m[2][2]

¿Puedo hacer esto?
#define FILAS 3
#define COLUMNAS 3
...
int matriz[FILAS][COLUMNAS];
mifuncion(matriz);
...
void mifuncion(int *m){
     ...
     m[1][0]=...
     ...
}

Respuesta
NO
Motivo: Cuando quiero pasar una matriz como parámetro a una función tengo que pasar además del puntero, las dimensiones de esa matriz ya que el puntero no tiene ninguna información acerca de cuántas columnas tiene la matriz y por tanto no sabe dónde terminan las filas.
Cuando he puesto m[1][0], sintácticamente es correcto, pero el compilador en ese punto como no sabe cómo de larga es una fila (es decir, cuántas columnas tiene la matriz), no tiene ni idea de a qué componente de la matriz tiene que acceder porque no sabe cuánto desplazarse en memoria.
Es decir, existe m[0][0],m[0][1], m[0][2]...¿Y m[0][1000]? ¿o paramos en m[0][29]? Si no sé cómo de larga es una fila, no sé dónde está almacenado en memoria la componente [1][0] y por tanto no puedo acceder así a los elementos guardados en una matriz.
¿Cómo lo hago entonces? Pasasando puntero (m), nmúmero de filas (f) y número de columnas (c).
El acceso a la componente [1][0] se hace como *(m+c*1+0), o como m[c*1+0] (sí, accediendo la matriz como si fuera un vector, menudo lío, je, je. Bienvenidos a C).
ejemplo [0][1] > *(m+c*o+1)
ejemplo [1][2] > *(m+c*1+2)

Paso de matrices como parámetros
#define FILAS 3
#define COLUMNAS 3
...
int matriz[FILAS][COLUMNAS];
mifuncion(matriz, FILAS, COLUMNAS);
...
void mifuncion(int *m, int f, int c){
     ...
     *(m+c*2+1)=...
     /* Equivalente a m[2][1] o a m[c*2+1]*/
     ...
}

Punteros y registros
'->': Operador especial para acceder a los campos de un regitro que es apuntado por un puntero.
Ejemplo de uso:
struct fecha{
     int dia;
     int mes;
     int agno;
};
struct fecha hoy;
struct fecha *phoy;
phoy=&hoy;
/* a continuación, 3 formas de hacer lo mismo: */
hoy.dia=28;
phoy->dia=28;

punteros y cadenas de caracteres
Recordar que en C una cedena de caracteres no es más que un vector de caracteres que termina en '\0' (para indicar donde termina la información útil que hay en ella).
Por tanto las cadenas de caracteres e tratan exactamente igual que los vectores.
Pese a ello hay algunas funciones para hacer las cosas más sencillas (que no es necesario emplear para nada). De ellas las básicas son strcat (concatenar), strcmp (comparar), strcpy (copiar) y strlen (tamaño útil de la cadena). Las demás rara vez se usan.

jueves, 8 de enero de 2015

Punteros en C

0

Después de 9 días de faltar a clase por aumento de trabajo (pocas vacaciones he tenido.. :( ) Hay varias cosas que necesitare para poner al día el blog. Va a ser mucho de golpe, preparados!!

Ejercicio introductorio
Escribe una función en notación algorítmica que devuelva el factorial de un número natural introducido como parámetro
 
funcion factorial(n:entero) devuelve entero
{Pre: n>0}
Variables
            resultado:entero;
            indice:entero;
Principio
            resultado:=1;
            para indice:=2;indice menor que n;indice++
                        resultado=resultado*indice;
            devuelve resultado
Fin

¿Otra manera?
¿Existe otra manera cualitativamente distinta de hacer lo que nos han pedido, que suponga al mismo tiempo una forma distinta de pensar en algoritmo para dar solución a problemas?
 
Sí, existe otra forma, que además es más intuitiva, y hace que podamos resolver problemas con algoritmos que nos resultan más sencillos de pensar.
 
Solución recursiva
funcion factorial (n:entero) devuelve entero
{Pre: n>0}
Principio
            si n=1
                        entonces
                                   devolver(1);
                        si no
                                   devolver (n*factorial(n-1);
            fsi
Fin
Hasta ahora conocíamos violaciones de segmento, ahora podemos generar desbordamiento de pila (por cierto, nombre de un muy buen foro de programación: http://stackoverflow.com )
Llamadas recursivas
n*factorial(n-1);
(n-1)*factorial(n-1);
(n-1)*factorial(n-2);
(n-1)*factorial(n-3);
3*factorial(2);
2*factorial(1);
1;
Ejercicio. 
Escribe una función que calcule el máximo común divisor (mcd) de dos números naturales, a y b, sabiendo que mcd(a,b)=mcd(b, a MOD b) si a>=b, y en caso contrario, mcd(a, b)=mcd(a, b MOD a). Da una solución recursiva.
Ejemplo à mcd(60, 45) = mcd(45, 15) = mcd(15,0)
Solución:
funcion mcd(a, b:entero) devuelve entero
{ Pre: a>=0, b>=0}
Principio
            si a=0
                        entonces devolver(b);
                        si no
                                    si b=0
                                                entonces devolver(a)
                                                            si no
                                                                        si a>b
                                                                                    entonces devolver (mcd(b,a MOD b));
                                                                                    si no devolver (mcd(a,b MOD a));
                                                                        fsi
                                    fsi
            fsi
fin
 
Algoritmo recursivo
Un algoritmo recursivo debe tener:

- Un tratamiento de todos los casos triviales que puedan darse en el problema a resolver. Dicho tratamiento no puede hacer llamadas recursivas y sí tiene que dar una solución inmediata a esos casos triviales.
-  Un tratamiento del(los) casos no trivial(es). Dicho tratamiento hará uso de una ley de recurrencia que mediante una fórmula o conjunto de acciones u operaciones resolverá el caso no trivial mediante llamadas a la propia función (o procedimiento) con parámetros “más pequeños” que converjan a uno de los casos triviales.
 
Para que el caso sea válido y funcione, cada llamada recursiva debe de hacer que la siguiente llamada se aproxime más a un caso trivial de forma que al final se llegue a dicho caso.
 
Tipos de algoritmos recursivos
Lineales. Cada invocación genera una nueva invocación y sólo una (excepto la última, claro). Un ejemplo es el anterior ejercicio del factorial.

- Final. Lo último que hace el algoritmo es precisamente esa invocación.
- No final. Tras la invocación aún hay que hacer algún cálculo en el resultado de la invocación. El ejercicio de factorial sería no lineal, ya que tras la invocación hay que hacer la multiplicación
Múltiples. Una misma invocación puede generar más de una invocación, por ejemplo, un ejercicio de calcular Fibonacci.
 
Inconvenientes
En general las soluciones recursivas son:

- Menos eficientes que las iterativas
- Más claras y sencillas que las iterativas
 
Lo bueno es pensar en recursivo e implementar en iterativo.
 
Podemos transformas en muchos casos los algoritmos recursivos en iterativos con más o menos dificultad.
 
Gracias Inazio Claver por cubrirme!!
Oh bueno, no he perdido mucha teoría solo horas y horas para adelantar trabajos, ya voy dos hojas de ejercicios retrasada :_(

Punteros en C
Los punteros es algo que cada lenguaje de programación trata de una forma especifica, aunque lo que se puede hacer en uno, normalmente se suele poder hacer en otro de una u otra manera.

Es por ello, que al ser algo especifico de programación, que vamos a verlo para el caso especifico de C, aunque algunas cosas podrían ser generalizables a otros lenguajes (pero muchas no).

Variables estáticas y dinámicas
En general, al programar, puedo hacer uso de dos tipos de variables:
- estáticas: La memoria que utilizan se reserva en tiempo de compilación. Ventaja: sencillez.
          int matriz[5][5];
- dinámicas: La memoria se reserva en tiempo de ejecución. Ventajas: flexibilidad (estoy definiendo una matriz de cualquier tamaño) y permiten la creación de estructuras de datos dinámicas ( que es un mecanismo más complejo que el visto ahora con las estructuras estáticas).
          int*mariz;
          ...
          matriz=malloc(sizeof(int)*5*5);
Para utilizar variables dinámicas es preciso disponer de un mecanismo para acceder a la memoria del ordenador. Ese mecanismo es precisamente el uso de punteros.

Concepto de puntero
Cuando tengo una variable, hay tres datos que están relacionados en ella:
- Tipo: Directamente relacionado con el tamaño del espacio que se reserva en memoria para ella.
- Valor que contiene.
- Dirección: Ubicación en memoria.
Un puntero es una variable que almacena la dirección de memoria de otra variable.
Es como una flecha que apunta a otra variable.

Punteros: dos operadores
Operador dirección (&): Nos devuelve la dirección de una variable.
Operador contenido o indirección (*): Nos permite acceder al contenido de una variable a la que está apuntando un puntero.

Declaración de punteros
Hay que indicar el tipo de la variable a la que apuntara, el nombre del puntero, y utilizar el símbolo * para indicar que es un puntero.
Ejemplo:
int valor;
int *puntero;
puntero=&valor;
valor=5;
*puntero=5; /*Las dos instrucciones hacen lo mismo*/
valor: 5
puntero: *

Más sobre punteros
¿Cuál es la diferencia?
- punteros=5; (Modificado a dónde apunta el puntero)
- *puntero=5; (Modifico el valor de la variable a la que apunta el puntero)
Hay que inicializar los punteros para que apunten a una dirección de memoria antes de utilizarlos.
- int *puntero;
  *puntero=7;
- ¿Dónde apunta el puntero? ¿Qué estoy modificando? Exacto, no lo sé ni yo, así que esto al Sistema Operativo no le va a gustar y seguro que se enfada (abortándome el programa).
Valor NULL: es un valor que se usa para indicar que un puntero no apunta a ningún sitio.
- int *puntero=NULL;
¿Qué operaciones puedo hacer datos apuntados? Las mismas que con el correspondiente tipo de datos.

Operaciones básicas con punteros
Asignación
- Hacer que el puntero apunte a una dirección de memoria.
- p1=p2; ojo, p1 pasa a contener la dirección de memoria contenida en p2.
- implicaciones:
  * Los vectores hay que copiarlos componente a componente.
  * Si copiamos el puntero, no hemos copiado la variable.

Comparación
- Ver si dos punteros apuntan al mismo lugar.
- p1==p2 no es lo mismo que *p1==*p2

Suma, resta
- Se utilizan para recorrer estructuradas de datos.
- p1++ (apuntará al siguiente carácter de una cadena)

Inicialización del valor de un puntero
Tengo dos opciones:
- Asignar la dirección de otra variable del programa:
  int valor;
  int *puntero;
  puntero=&valor;
- Pedir al sistema memoria para una variable nueva.
  * Es precisamente la opción empleada para utilizar variables dinámicas.
  * C ofrece funciones para obtener memoria del Sistema Operativo de forma dinámica y liberarla cuando ya no es necesaria.

Generación y destrucción de variables dinámicas
#include <stdlib.h> /*necesario para asignación dinámica de memoria*/
...
struct fecha {
     int dia;
     int mes;
     int agno;
};
struct fecha *pFecha;
...
pFecha=(struct fecha *) malloc (sizeof(struct fecha));
if (pFecha==NULL){
     printf("No hay suficiente memoria\n");
}
else {
     ...
     free (pFecha):
     ...
}
...

malloc y free
pFecha=(struct fecha *) malloc (sizeof(struct fecha));
- malloc reserva los bytes que indiquemos en el parámetro que le pasamos (Precisamente para ello usamos la función sizeof pasándole como parámetro el tipo correspondiente. Así reservamos espacio justo para una variable de ese tipo).
- malloc devuelve un puntero genérico ( o NULL si no hay memoria suficiente).
- Tras llamar a malloc hay que hacer una conversión explícita de tipos para convertir ese puntero genérico en un puntero específico al tipo de datos que estamos manejando (en este caso en un puntero a struct fecha).
free(pFecha)
- free libera la memoria a la que apunta el puntero que le pasamos como parámetro.
- liberará más o menos memoria en función del tipo de datos del que sea el puntero que le pasamos.

Paso de parámetros por referencia a una función
Los punteros entre otras cosas dan soporte ara poder pasar parámetros por referencia a una función:
  ...
  float perim, área;
  circulo(radio, &perim, &área);
  ...
  void circulo (float r, float *p, float *a){
  *p=2*Pl*r;
  *a=Pl*r*r;
  }

Si la función llamara a otra función y hubiera que pasar de nuevo "a" por referencia, no habría que poner "&" delante de "a", ya que "a" es ya un puntero y por tanto una dirección.

Punteros y vectores
char *p, c, v[5]; /*Definimos un puntero a carácter, un carácter, y un vector de 5 caracteres*/
c=*p; /* Asigno a c lo apuntqado por p*/
p=&c; /* Asigno a p la dirección de c*/
/* Al definir un vector v[5] se queda guardada la dirección inicial del vector en la constante v*/
p=v;
p=&v[0]; /* Esta línea y la anterior son equivalentes*/
/* Del mismo modo p+4 es exactamente lo mismo que &p[4]*/
/* Y *(v+4) equivale a v]*/

Recorriendo vectores con punteros
* Le estaríamos sumando a p 1:
char*p;
p=p+1;
* Le estaríamos sumando a p 4:
int *9;
p=p+1 /* si, uno vale por cuatro*/

Aclarando un poco las cosas
int vector[4]

El compilador reserva cuatro enteros consecutivos en memorial.
Almacena en la variable vector la dirección del primer elemento del vector.
Acceso a los elementos:
vector [0]     *(vector)
vector [1]     *(vector+1)
vector [2]     *(vector+2)
vector [3]     *(vector+3)

La variable vector es como un puntero, con la única diferencia de que se ha reservado además espacio para sus componentes.

Paso de vectores como parámetros
Cuando pasamos un vector a una función, lo estamos pasando implícitamente por referencia, ya que un vector y un puntero, a fin de cuentas, son lo mismo (o casi).

Como parámetro actual ponemos la variable vector (que como acabamos de ver no es más que un puntero).

Como parámetro formal, hasta ahora hemos hecho apaños ya que no sabíamos muy bien lo que eran los punteros ni su relación con los vectores, pero a partir de ahora basta con poner un puntero al tipo del que sean las componentes del vector. Dentro de la función podré acceder a las 2componentes de ese puntero" sin ningún problema.

Recordar que al ser un paso por referencia y al estar pasando punteros, todos los cambios que haga el vector quedarán hechos en el vector original.

Recordar además que existe un motivo importante para que un vector se pase siempre por referencia, y es que de hacerse por valor se estarían duplicando las necesidades de memoria.

Paso de parámetros: Ejemplo
main(){
     char cadena[50];
     char nueva[50];
     ...
     QuitaEspacios (cadena, nueva);
     /* cadena y nueva son ya direcciones*/
     ...
}
void QuitarEspacios (char *origen, char *destino){
    ...
    destino[3]=origen[7];
    ...
}

lunes, 24 de noviembre de 2014

Tema 5c

0

Función Open


Uso de fopen()
FILE*fich;
fich=fopen("ejemplo.txt", "r");
if (fich==NULL)
     printf("Error en la apertura del fichero\n");
else
{
...
}

Lectura y escritura de un fichero en modo texto
Igual que la lectura/escritura por teclado/pantalla pero haciéndolo sobre un fichero.
Se usan las funciones fprintf y fscanf en vez de printf y scanf.
- Tienen un parámetro más (el primero) que indica en qué fichero escribir o leer. Por lo demás, funcionan exactamente igual que las otras dos.
fprintf(fich, "%i", numero);
fscanf(fich, "%i", &numero);

Lectura y escritura de un fichero en modo binario
Los datos se vuelcan tal y como se encuentran en memoria.
Adecuado para datos complejos (structs y matrices).
Un fichero binario no es editable (Veremos símbolos raros).
Dos nuevas funciones:
- fwrite(ptdato, N, k, fichero)
-fread(ptdato, N, k, fichero)
en ambos casos:
* ptdato: puntero a donde se encuentran los datos.
* n: tamaño del elemento.
* k: número de elementos.
* fichero: puntero de tipo FILE.
Ambas funciones devuelevb el número de elementos leídos/escritos correctamente. Si el número es menor del esperado algo ha pasado:
- Error.
- Se ha llegado al final del fichero (en el caso de lectura).

fread() y fwrite()
Aquí es donde es realmente útil la función sieof() que ya hemos empleado alguna vez.
Ejemplo:
FILE*fich;
struct medida
{
     int hora;
     int minuto;
     float valor;
}*dato;
...
fread(dato, sizeof(struct medida), 1, fich);
...
fwrite(dato, sizeof(struct medida), 1, fich);
...

Cierre de un fichero
Operación muy importante que supone el fin del tratamiento del fichero.
En caso de escritura, asegura que se han escrito todos los datos en el disco.
fclose(fich);

feof()
Control de lectura: para saber cuándo se llega al final del fichero existente la función feof().
Devuelve
- cierto cuando ya hemoos leído todos los datos del fichero.
- Falso cuando aún quedan por leer.
Esquema: Importantisimo mantener el esquema!!
leer(fich, dato);
mientras que (!feof(fich))
     procesar_dato();
     leer(fich, dato);
fin_mientras;
Es decir, el fin de fichero es como si fuera un carácter que se lee, y es entonces cuando comprobamos a ver si ya hemos llegado al final.

Ejercicio
Tenemos un fichero de texto que contienen muchos enteros (eso sí, esa cantidad es múltiplo de 10). Se trata de ir leyendo datos de ese fichero de texto e ir calculando y mostrando por pantalla las medias ide los números de 10 en 10. Es decir, primero la media de los 10 sogiguientes, y así hasta que el fichero se termine.

Solución
#include <stdio.h>
main()
{
     FILE*f;
     int dato, suma, i;
     f=fopen("fichero.txt","r");
     if (f==NULL)
          printf("Error en la apretura\n");
     else
     {
          fscanf(f,"%i",&dato);
          while (!feof(f))
           {
                suma=0;
                for (i=0;i<10;i++)
                {
                      suma+=dato;
                      fscanf(f,"%i", &dato);
                 }
                 printf("La media es %d\n", suma/10);
             }
             fclose(f);
     }
}

Ejercicio
Tenemos un fichero de registros "fichero.dat" cuyas componentes están definidas según la declaración siguiente:
typedef struct registro 1
{
     char partido[60];
     char localidad[60];
     int candidatos;
} ANTES;
Se quiere sustituir la estructura del registro por l siguiente:
typedef struct registro 1
{
     char partido[60];
     char localidad[60];
     int candidatos, elegidos;
} DESPUES;
Escribe un programa que modifique la estructura y trasvase toda la información del fichero primitivo al nuevo "nuevo.dat", inicializando a 0 el nuevo campo creado.

Solución

...
ANTES antes;
DESPUES despues;
FILE*old, *new;
old=fopen("fichero, dat","r");
new=fopen("nuevo.dat","w");
fread(&antes, sizeof(antes), 1, old);
while (!feof(old))
{
     strcpy(despues, partido, antes, partido);
     strcpy(despues, localidad, antes, localidad);
     despues.candidatos=antes.candidatos;
     despues.elegidos=0;
     fwrite(&despues, sizeof(despues), 1, new);
     fread(&antes, sizeof(antes), 1, old);
}
fclose(old);
fclose(new);
...


jueves, 6 de noviembre de 2014

Explicaciones

0

Introducen un texto por pantalla. ej. Hola, yo soy un texto. 1234 Y presionan enter. Hasta que no presionan enter el texto no va a parar hasta una sección de memoria. (Pasa lo mismo con la salida '\n')Si yo le digo lee un carácter, leerá H y mi variable c vale H, si repito el proceso, valdrá o, l, a, ' ', ','... 1... Si quiero que lea el 1234 como uno debo crear una variable entera e ir añadiendo los caracteres quitando el 0 en modo ASCII.
El carácter que yo he leído tiene su forma de carácter y su ASCII asociado, si lo imprimo con char veré la letra, si lo imprimo con int veras su valor numérico.

Es peligroso mezclar la lectura de carácter, con lectura de enteros.
Los enteros ignorar espacios, saltos de linea, cualquier cosa que haya. Los caracteres no.

Violación de segmento > cuando tu programa por un mal calculo intenta salirse de la memoria. El SO corta el programa o peor, el programa podría tener acciones no deseadas. Si yo me he definido un vector de 23 componentes ira de 0 a 22. La sección 23 no existe. la -1 menos, No puedo pedirla. Si la pido, es como si intentaras adueñarte de un campo de memoria que no te corresponde y el SO se defiende de lo que considerara un virus.

miércoles, 5 de noviembre de 2014

juego

0

Se que esta entrada sin el código no tiene sentido, pero lo tendré pronto, estoy trabajando en ello. Y pronto estará todo subido.

Seguimos creando un juego conecta 4. 
Y dado que el fichero se nos esta haciendo un poco grande, vamos a proceder a dividirlo.
Creando un fichero nuevo, aclaro que los ficheros de cabecera deben tener la terminación .h y los de código .c
En un fichero guardaremos el main '.c'. Y en otro el código de las funciones '.c'.
en el archivo o librería '.h' se ha guardado las variables #define , así como la llamada de las funciones. 
Para enlazar los ficheros se incluye en '.c': #include "contecta4Lib.h"
Para comprimir un programa que esta en varios archivos se deben comprimir todos los '.c' juntos, nombrándolos por separado: "gcc -o conecta4  main.c funciones.c". La librería no hace falta compilarla.

En el caso de que tuviéramos varias librerías y archivos de funciones, debes saber que en el archivo main. c debes incluir todas las librerías, y en las funciones.c solo la librería necesaria.



lunes, 3 de noviembre de 2014

Registros

0

Continuación tema 6

Ejemplo: números complejos 
Aqui voy a ser mala y cuando Inazio lo suba al blog lo copio y pego, porque muero de dolor de cabeza si copio esa letrita, que llevo toda la mñn para terminar el trabajo de sistemas de evolución de los sistemas operativos. :( 

Vector de registros, registro con vectores
Los tipos y los mecanismos para definir tipos los puedo combinar a mi antojo según mis necesidades.
Por ejemplo, podría tener un vector (o una matriz, incluso de dimensión superior a 3), para la que cada componente fuera un registro que guardara varios datos de tipos diferentes. Uno de ellos podría ser a su vez otro vector, u otro registro y así indefinidamente.
También podría tener un registro y que uno de sus campos fuera un vector pudiendo ser cada componente lo que me pudiera interesar, según el problema a resolver.
Por ejemplo, podría tener un vector de hospitales, cada hospital ser un registro donde guardo nombre, dirección, y un vector de médicos que trabajan en él y otro vector de pacientes que estoy atendiendo, y otro vector de habitaciones. Cada una de esas componentes sería de nuevo un registro con la información relevante que quisiera guardar sobre ellos.
El acceso a estas estructuras de datos se realiza encadenando operadores, por ejemplo, podría encontrar en mi programa expresiones como esta: hospitales [36], medicos [17], especialidad. Estaría accediendo a la especialidad que tiene el médico 17 del hospital 36.

...Tema 5
Registro en C: veámoslo con ejemplos (1)
strucu Structure1
{
     char c;
     int i;
     float f;
     double d;
};
int main ()
{
     struct Structure1 s1, s2;
     s1.c='a';
     s1.i=1;
     s1.f=3.14;
     s1.d=0.00093;
     s2.c='a';
     s2.i=1;
     s2.f=3.14;
     s2.d=0.00093;
}

Con registros si es necesario definirse "el tipo" antes que variables de ese tipo, para ello tenemos que usar la palabra reservada "struct".
Al declarar las variables de ese tipo, también hay que incluir la palabra struct.
En main (), se crean dos instancias de Structure1: s1 y s2. Cada una de ellas tiene su versión propia y separada de c, i, f y d. Dr modo que s1 y s2 representan bloques de variables completamente independientes.

Registros en C: veámoslo con ejemplos (2)
"Es una tontería"
¿Porque pone el mismo algo que no quiere que sepamos?

Registros en C: veámoslo con ejemplos (3)
Cuando pasemos un parámetro de tipo struct por referencia, dentro de la función la forma de acceder a cada campo sera usando '->' en vez de '.'.

typedef struct
{
     int i;
     float f;
}MITIPO;
void mifuncion(MITIPO*miparametro)
{
     ...
     miparametro->i=3;
     miparametro->f=6.0;
}
main ()
{
     MITIPO mivariable;
     ...
     mifuncion(&variable):
     ... mivariable.i...
     ...
}
y ahora nos pone un ejemplo con punteros, sin saber lo que es un puntero :/

Ejercicio
Rehaz el ejemplo validar una fecha, haciéndolo por referencia.

jueves, 30 de octubre de 2014

Lenguaje C

0

Caracteres
C hace normalmente un tratamiento muy sucio de los datos que almacena, mezclando representación interna y externa.
Una variable de tipo carácter, almacena internamente el valor ASCII del carácter. Externamente está esperando que le introduzca exactamente ese valor. 
Es al utilizar ciertas funciones de librería para representar esos caracteres por pantalla ciuando es interpretado ese valor y se muestran los caracteres tal cual. Yo en el programa puedo usar indistintamente 65, 'A', o '\65'. Para el lenguaje de programación C todo eso tiene el valor de 65.
Así ser esto así, yo puedo sumar y restar enteros y caracteres entre sí, o sólo caracteres, compararlos, etc. Ejemplo, la condición para indicar si una letra es mayúscula sería; (letra>='A' && letra<='Z')

Al parecer lo va a pasar más rápido de lo normal. Copio lo que se pueda!!

ctype.h
Existe un archivo de cabecera de la biblioteca estándar del lenguaje de programación C diseñado para operaciones básicas con caracteres. Contiene los prototipos de las funciones y macros para clasificar caracteres. Su uso no es necesario en absoluto ya que las cosas que hace son fácilmente programables.

Cadena de caracteres
Los stringhs en C son vectores de caracteres que tienen almacenado en algún punto el carácter '\0', que indica el fin de string.
Para declaraer una cadena de caracteres es necesario un carácter más que la cadena más larga que pueda contener, par dejar sitio para el carácter nulo del final de la cadena.
Las cadenas van entre comillas dobles.
Ejemplo: char v[6]="Lunes"
No es necesario añadir explícitamente el carácter nulo al final de las constantes de cadena, el compilador lo hace automáticamente.
Lectura de cadenas:
-char cadenas[255];
 scanf ("%s", cadena); /* No es necesario usar & porque cadena ya es un puntero*/
Escritura de cadenas:
-printf ("%i", cadena);

Conversión de cadenas: stdlib.h

Me distraje :/

double atof (cadena): Convierte una cadena de dígitos a double.
int atoi (cadena): Convierte una cadena de dígitos 
...

Manipulación de cadenas: string.h

Me falta un carácter

char*strcpy (s1, s2): Copia la cadena s2 en s1. Devuelbve s1.
char*strncpy (s1, s2, n): Copia si es posible n caracteres de la cadena s2 en s1. Devuelves s1.
char*strcat (s1, s2): Añade s2 a s1, machacando el valor final de s1, '\0'. Devuelve s1.
int strcmp (s1, s2): Compara las cadenas s1 y s2. Devuelve un número negativo si s1>...

Búsqueda en cadenas

Solo nombrare los tipos

char*strchr (s1, c):
size_t strcspn (s1, s2):
size_tstrspn (s1, s2):
char*strpbrk (s1, s2):
char*strrchr (s1, c):
char*strstr (s1, s2):
char*strtok (s1, s2): 

fin del tema 5 C, retomamos el tema 6 de teoría

Registros
Un registro es una agrupación o estructura de datos que me permiten almacenar agrupados diferentes datos que pueden ser de diferentes tipos.
Cuando yo quiero guardar información sobre cualquier cosa, suelo tener que guardar informaciones de tipos muy diversos que entre todos defienden cómo es esa cosa.
Por ejemplo, si quiero guardar información sobre diferentes coches que tengo guardados en un garaje procedentes de embargos de un banco, podría guardar modelo, mrca, color, matricula, kilometros, antiguedad, estado, etc. Cada uno de estos datos sería de tipos diferentes, y además no existe un orden concretro en el que deban ser almacenados esos datos, aunque si una asociación con lo que estoy guardando.
Para esto no podría utilizar un vector, incluso en el caso de que todos los datos fueran del mismo tipo, se tefieren todos a una misma realidad y concretamente a diferentes "subdatos"  de esa realidad, y me interesa guardar cada uno como una "subcaracteristica" de la cosa de la que estoy guardando información.
Un claro ejemplo de esto es un fecha, consta de día, mes y año, los tres son datos enteros, ahora bien, podría establecer limitaciones a los valores que pueden tomar esos tres datos. Pero no se me ocurriría guardarlos en un vector de tres componenetes, sino en un registro con tres campos que se llaman exactamente así: día, mes y agno.
Al igual que con los vectores, primero hay que declarar el tipo, con los campos que va a tener y posteriormente declarar las variables que serán de ese tipo.
Para acceder después a un campo concreto de un registro en el programa, se hará poniendo el nombre de la variable y el nombre del campo, separados por un punto.

Declaración y uso de registros
tipos
     <nombre_tipo>=          registro
                                                       <nombre_campo1>:<tipo_1>;
                                                       <nombre_campo_2>:<tipo2>;
                                                        ...
                                                       <nombre_campo_n>:<tipo_n>;
                                           freg;
variabloes
     <nombre_variable_1>, <nombre_variable_2>:<nombre_tipo>;
     <nombre_variable_3>:<nombre_tipo>;
     ...
principio
...
... <nombre_variable_1>.<nombre_campo_3>...
...
fin

Ejemplos (1)
tipos
     cad20=cadena[20];
     tipo_sexo=(varon,hembra);
     tipo_fecha=             registro
                                                  dia:1,31;
                                                  mes:1,12;
                                                  anyo: 0, 3000;
                                    freg;
    tipo_persona=         registro
                                                nombre, apellido1, apellido2, cad20;
                                                sexo tipo_sexo,
                                                fecha_nacimiento:tipo_fecha;
                                    freg;
    tipo_complejo_1=   registro
                                            parte_real, parte_imaginaria:real;
                                    freg;
    tipo_complejo_2=   registro
                                            modulo, argumentación real;
                                    freg;
variables
     ayer, hoy: tipo:fecha;
     yo, tu, el: tipo_persona;
    z: tipo_complejo_1;
    w: tipo_complejo_2;

Ejemplos (2)
principio
     ...
     ayer.dia:=13;
     ayer.mes:=3;
     ayer.anyo:=1988;
     hoy.día:=ayer.dia+1;
     el.sexo:=varon;
    el.fecha_nacimiento:=ayer;
    z.parte_real:=w.modulo*cos(w.argumento);
    z.parte_imaginaria:=w.modulo*sin(w.argumento);
    ...
fin

Ejercicios
Dado un tipo complejo con parte real y parte imaginaria, crear los siguientes procedimientos:
    tipos
          tipo.complejo:registro
               parte_real, parte_imaginaria:real;
         freg;
procedimiento crear_complejos(E v1:real, E v2:real, sx:tipo_complejo)
procedimiento sumar_complejos(Ex:tipo_complejo, E y:tipo_complejo. sz:tipo_complejo)
procedimiento multiplicar_complejos (Ex:tipo_complejo, E y:tipo_complejo. sz:tipo_complejo)

Etiquetas actuales

BD (67) DEF (64) PROG (64) SQL (44) Java (29) PRACTICAS (20) php (18) DI (16) PRESTASHOP (16) PROGRAMACIÓN WEB (16) HTML (13) SGE (12) ERP (9) CONSULTAS (8) css (8) Linux (5) XML (5) Android (4) PDM (4) C (3) NetBeans (3) PSP (3) SMARTY (3) comandos (3) HOOK (2) POST (2) XSD (2) cURL (2) JS (1) MEDIA-QUERYS (1) PDO (1) RESPONSIVE (1) TPL (1) TRADUCCIÓN (1) app_inventor (1)

Todas las etiquetas

EJER (78) BD (67) DEF (64) PROG (64) SQL (44) c# (40) Programación (39) Ficheros (36) Java (29) bases de datos (21) PRACTICAS (20) lenguajes de marcas (19) AD (18) Entorno de desarrollo (18) php (18) PROCEDIMIENTOS (17) DI (16) FORM (16) PRESTASHOP (16) PROGRAMACIÓN WEB (16) lenguaje C (16) E/R (14) HTML (13) SGE (12) Sistemas informáticos (10) ERP (9) CONSULTAS (8) TRANSACCIONES (8) TRIGGER (8) VISUAL BASIC (8) css (8) FUNCIONES (7) html5 (6) Ada (5) EXAMEN (5) Linux (5) XML (5) estructuras (5) Android (4) DISEÑO (4) INTERFAZ (4) LOG (4) OpenBravo (4) PDM (4) ACTUALIZAR (3) C (3) DIAGRAMA (3) Directorios (3) NEW (3) NOR (3) NetBeans (3) OLD (3) PSP (3) SMARTY (3) comandos (3) css3 (3) AISLAMIENTOS (2) C++ (2) CONTROLERRORES (2) ELIMINAR (2) HOOK (2) INSERTAR (2) INST (2) MULTITABLA (2) POST (2) RECURSIVIDAD (2) SUBCONSULTAS (2) VISTAS (2) XSD (2) cURL (2) punteros (2) AJENA (1) BLOQUEOS (1) Byte (1) CREACION (1) CRM (1) Configuración (1) Controles (1) Datos (1) GOTFOCUS (1) IMAGENES (1) INDICES (1) JS (1) Lenght (1) MEDIA-QUERYS (1) Mingw (1) MonoDeveloped (1) OPTIMISTA (1) PDO (1) PESIMISTA (1) RESPONSIVE (1) SPEAK (1) Scanner (1) Serializacion (1) Streams (1) System (1) TPL (1) TRADUCCIÓN (1) USUARIOS (1) UseSystemPasswordChar (1) app_inventor (1) char (1) examenes (1) libreoffice (1) make (1) redes (1)