Fundamentos de C - Lección 5
ESTRUCTURAS CONDICIONALES
editarIf
editarif (expresion) { ............ ............ } else { ........... ........... }
Switch
editarswitch (variable) { case cte1 : ........... ........... break; case cte2 : ........... ........... break; .................. .................. default : ........... ........... }
Switch sólo puede comprobar la igualdad.
BUCLES
editarFor
editarfor (inicialización; condición; incremento) sentencia inicialización ----> asignación condición ----> expresión relacional
Ejemplo:
for (x=1; x<=100; x++) printf ("%d",x); Imprime los numeros del 1 al 100
While
editarwhile (condición) sentencia;
Ejemplo:
while (c!='A') c=getchar( );
Do / While
editarAnaliza la condició al final.
do { ........... ........... } while (condicion);
Break
Tiene dos usos: - para finalizar un case en una sentencia switch. - para forzar la terminación inmediata de un bucle.
Exit
Para salir de un programa anticipadamente. Da lugar a la terminación inmediata del programa, forzando la vuelta al S.O. Usa el archivo de cabecera stdlib.h
Ejemplo:
editar#include <stdlib.h> main (void) { if (!tarjeta_color( )) exit(1); jugar( ); }
Continue
Hace comenzar la iteración siguiente del bucle, saltando así la secuencia de instrucciones comprendida entre el continue y el fin del bucle.
do { scanf("%d",&num); if (x<0) continue; printf("%d",x); } while (x!=100); Funciones tipo nombre_funcion (lista de parametros) { ............ ............ }
tipo, especifica el tipo de valor que devuelve la sentencia return de la función. 8 Llamada por valor Copia el valor de un argumento en el parámetro formal de la subrutina. Los cambios en los parámetros de la subrutina no afectan a las variables usadas en la llamada.
int cuad (int x); main ( ) cuad (int x) { int t=10; x=x*x; printf ("%d %d",cuad(t),t); return(x); return 0; } }
Salida es << 100 10 >> Llamada por referencia Es posible causar una llamada por referencia pasando un puntero al argumento. Se pasa la dirección del argumento a la función, por tanto es posible cambiar el valor del argumento exterior de la función.
int x,y; inter (int *x,int *y) inter (&x,&y); { int temp; temp=*x; *x=*y; *y=temp; }
Arrays
editarTodos los arrays tienen el 0 como índice de su primer elemento. char p [10]; array de caracteres que tiene 10 elementos, desde p[0] hasta p[9]. Para pasar arrays unidimensionales a funciones, en la llamada a la función se pone el nombre del array sin índice. Ejemplo: main ( ) Si una función recibe un array unidimensional, se puede { declarar el parámetro formal como un puntero, como un int i[10]; array delimitado o como un array no delimitado. func1 (i); } func1 (int *x) /puntero/ func1 (int x[10]) /array delimitado/ func1 (int x[ ]) /array no delimitado/ 9
Inicialización de arrays
editarForma general de inicialización de un array: tipo nombre_array [tamaño] = {lista de valores}; lista de valores, es una lista de constantes separadas por comas, cuyo tipo es compatible con el tipo del array. La primera constante se coloca en la primera posición del array, la segunda constante en la segunda posición y así sucesivamente. Ejemplo: int i[10]={1,2,3,4,5,6,7,8,9,10}; Los arrays de caracteres que contienen cadenas permiten una inicialización de la forma: char nombre_array [tamaño]="cadena"; Se añade automáticamente el terminador nulo al final de la cadena.
Ejemplo:
editarchar cad[5]="hola"; equivalentes char cad[5]={'h','o','l','a','\o'}; Es posible que C calcule automáticamente las dimensiones de los arrays utilizando arrays indeterminados. Si en la inicialización no se especifica el tamaño el compilador crea un array suficientemente grande para contener todos los inicializadores presentes. char e1[ ]="error de lectura \n";
Cadenas
editarAunque C no define un tipo cadena, estas se definen como un array de caracteres de cualquier longitud que termina en un carácter nulo ('\0'). Array que contenga 10 caracteres: char s[11]; Una constante de cadena es una lista de caracteres encerrada entre dobles comillas. Funciones de manejo de cadenas Archivo de cabecera string.h char *strcpy (char *s1, const char *s2); copia la cadena apuntada por s2 en la apuntada por s1. Devuelve s1. char *strcat (char *s1, consta char *s2); concatena la cadena apuntada por s2 en la apuntada por s1, devuelve s1. int strlen (const char *s1); devuelve la longitud de la cadena apuntada por s1. int strcmp (const char *s1, const char *s2); compara s1 y s2, devuelve 0 si con iguales, mayor que cero si s1>s2 y menor que cero si s1<s2. Las comparaciones se hacen alfabéticamente. 10
Arrays Bidimensionales
editarSe declaran utilizando la siguiente forma general: tipo nombre_array [tamaño 2ª dim] [tamaño 1ª dim]; Ejemplo -----> int d [10][20]; Cuando se utiliza un array bidimensional como argumento de una función realmente sólo se pasa un puntero al primer elemento, pero la función que recibe el array tiene que definir al menos la longitud de la primera dimensión para que el compilador sepa la longitud de cada fila. Ejemplo: función que recibe un array bidimensional de dimensiones 5,10 se declara así: func1 (int x[ ][10]) { .................... }
Arrays y Punteros
editarUn nombre de array sin índice es un puntero al primer elemento del array. Ejemplo: Estas sentencias son idénticas: char p[10]; - p - &p[0] int *p, i[10]; p=i; ambas sentencias ponen el valor 100 en el sexto elemento de i. i[5]=100;
- (p+5)=100;
Esto también se puede aplicar con los arrays de dos o más direcciones. int a[10][10]; a=&a[0][0]; a[0][4]=*((*a)+4);
Memoria dinámica
editarMalloc (n) reserva una porción de memoria libre de n bytes y devuelve un puntero sobre el comienzo de dicho espacio. Free (p) libera la memoria apuntada con el puntero p. Ambas funciones utilizan el archivo de cabecera stdlib.h Si no hay suficiente memoria libre para satisfacer la petición, malloc ( ) devuelve un nulo. 11
Ejemplo:
editarchar *p; p=malloc(1000);
Estructuras
editarLa forma general de una definición de estructura es: struct etiqueta { tipo nombre_variable; tipo nombre_variable; ............................. ............................. } variables _de_estructura
Ejemplo:
editarstruct dir { char nombre[30]; char calle[40]; char ciudad[20]; char estado[3]; unsigned long int codigo; } info_dir; A los elementos individuales de la estructura se hace referencia utilizando . (punto).
Ejemplo:
editarinfo_dir.codigo = 12345; Forma general es: nombre_estructura.elemento Una estructura puede inicializarse igual que los vectores: struct familia { char apellido[10]; char nombrePadre[10]; char nombreMadre[10]; int numerohijos; } fam1={"Garcia","Juan","Maria",7}; Arrays de estructuras Se define primero la estructura y luego se declara una variable array de dicho tipo.
Ejemplo:
editarstruct dir info_dir [100]; Para acceder a una determinada estructura se indexa el nombre de la estructura: info_dir [2].codigo = 12345; 12
Paso de estructuras a funciones
editarCuando se utiliza una estructura como argumento de una función, se pasa la estructura íntegra mediante el uso del método estándar de llamada por valor.
Ejemplo:
editarstruct tipo_estructura { int a,b; char c; }; void f1 (struct tipo_estructura param); main ( ) { struct tipo_estructura arg; arg.a = 1000; f1(arg); return 0; } void f1 (struct tipo_estructura param) { printf ("%d",param.a); }
Punteros a estructuras
editarDeclaración: struct dir * pruntero_dir; Existen dos usos principales de los punteros a estructuras: 1) para pasar la dirección de una estructura a una función. 2) para crear listas enlazadas y otras estructuras de datos dinámicas. Para encontrar la dirección de una variable de estructura se coloca & antes del nombre de la estructura.
Ejemplo:
editarstruct bal { float balance; char nombre[80]; } persona; struct bal *p; p = &persona; (coloca la dirección de la estructura persona en el puntero p) No podemos usar el operador punto para acceder a un elemento de la estructura a través del puntero a la estructura. Debemos utilizar el operador flecha -> p -> balance
Tipo enumerado
editarenum identificador {lista de constantes simbólicas};
Ejemplo:
editarenum arcoiris {rojo, amarillo, verde, azul, blanco}; (realmente asigna rojo=0, amarillo=1, ...) printf ("%d %d", rojo, verde); imprime 0 2 en pantalla Podemos especificar el valor de uno o más símbolos utilizando un inicializador. Lo hacemos siguiendo el símbolo con un signo igual y un valor entero. enum moneda {penique, niquel, diez_centavos, cuarto=100, medio_dolar, dolar}; Los valores son: penique 0, niquel 1, diez_centavos 2, cuarto 100, medio_dolar 101, dolar 102 (Libro pag. 167 )
Punteros
editarint x=5, y=6; int *px, *py; px=py; copia el contenido de py sobre px, de modo que px apuntará al mismo objeto que apunta py.
- px=*py; copia el objeto apuntado por py a la dirección apuntada por px.
px=&x; px apunta a x. py=0; hace que py apunte a nada (NULL). px++; apunta al elemento siguiente sobre el que apuntaba inicialmente Ejemplo: Se puede sumar o restar enteros a y de punteros. p1=p1+9; p1 apunta al noveno elemento del tipo p1 que está más allá del elemento al que apunta actualmente. 13 14
Punteros y arrays
editarchar cad[80], *p1; p1 = cad p1 ha sido asignado a la dirección del primer elemento del array cad. Para acceder al quinto elemento de cad se escribe: cad[4] o *(p1+4) Arrays de punteros Array de punteros a enteros: int *x [10]; Para asignar la dirección de una variable entera llamada var al tercer elemento del array de punteros, se escribe: x[2]=&var; Para encontrar el valor de var:
- x[2]
Punteros a punteros
editarpuntero ----------> variable Indirección simple puntero ---------> puntero ---------> variable Indirección múltiple float **balancenuevo; balancenuevo no es un puntero a un número en coma flotante, sino un puntero a un puntero a float. Ejemplo: main(void) { int x, *p, **q; x=10; p=&x; q=&p; printf("%d",**q); /* imprime el valor de x */ return 0; } 15
E/S por consola
editargetche ( ) lee un carácter del teclado, espera hasta que se pulse una tecla y entonces devuelve su valor. El eco de la tecla pulsada aparece automáticamente en la pantalla. Requiere el archivo de cabecera conio.h putcahr ( ) imprime un carácter en la pantalla. Los prototipos son: int getche (void); int putchar (int c);
Ejemplo:
editarmain ( ) /* cambio de mayúscula / minúscula */ { char car; do { car=getche( ); if (islower(car)) putchar (toupper (car)); else putchar (tolower (car)); } while (car=!'.') } Hay dos variaciones de getche ( ) : - Getchar ( ): función de entrada de caracteres definida por el ANSI C. El problema es que guarda en un buffer la entrada hasta que se pulsa la tecla INTRO. - Getch ( ): trabaja igual que getche ( ) excepto que no muestra en la pantalla un eco del carácter introducido. gets ( ) y puts ( ) Permiten leer y escribir cadenas de caracteres en la consola. gets ( ) lee una cadena de caracteres introducida por el teclado y la situa en la dirección apuntada por su argumento de tipo puntero a carácter. Su prototipo es: char * gets (char *cad);
Ejemplo:
editarmain ( ) { char cad[80]; gets (cad); printf ("La longitud es %d", strlen (cad)); return 0; } puts ( ) escribe su argumento de tipo cadena en la pantalla seguido de un carácter de salto de línea. Su prototipo es: 16 char * puts (const char *cad); E/S por consola con formato printf ( ) El prototipo de printf ( ) es: int printf (const char *cad_fmt, ...); La cadena de formato consiste en dos tipos de elementos: caracteres que se mostrarán en pantalla y órdenes de formato que empiezan con un signo de porcentaje y va seguido por el código del formato.
%c un único carácter %d decimal %i decimal %e notación científica %f decimal en coma flotante %o octal %s cadena de caracteres %u decimales sin signo %x hexadecimales %% imprime un signo % %p muestra un puntero
Las órdenes de formato pueden tener modificadores que especifiquen la longitud del campo, número de decimales y el ajuste a la izquierda.
Un entero situado entre % y el código de formato actúa como un especificador de longitud mínima de campo. Si se quiere rellenar con ceros, se pone un 0 antes del especificador de longitud de campo. %05 rellena con ceros un número con menos de 5 dígitos. %10.4f imprime un número de al menos diez caracteres con cuatro decimales. Si se aplica a cadenas o enteros el número que sigue al punto especifica la longitud máxima del campo. %5.7s imprime una cadena de al menos cinco caracteres y no más de siete. scanf ( ) Su prototipo es:
int scanf ( ) (const char *cadena_fmt, ...);
Ejemplo:
editarscanf ("%d",&cuenta);
Aritmética de punteros
editarSinopsis
editarLa aritmética de punteros se limita a suma, resta, comparación y asignación. Las operaciones aritméticas en los punteros de tipoX (punteros-a-tipoX) tienen automáticamente en cuenta el tamaño real de tipoX. Es decir, el número de bytes necesario para almacenar un objeto tipoX [2]. Por ejemplo, suponiendo una matriz de double con 100 elementos, si ptr es un puntero a dicha matriz, la sentencia ptr++; supone incrementar el Rvalue de ptr en 6.400 bits, porque el tamaño de la matriz es precisamente 100x64 bits.
Nota: no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquí sería puntero-a-double).
La aritmética realizada internamente en los punteros depende del modelo de memoria en uso y de la presencia de cualquier modificador superpuesto.
Las operaciones que implican dos punteros exigen que sean del mismo tipo o se realice previamente un modelado apropiado .
Operaciones permitidas
editarSean ptr1, ptr2 punteros a objetos del mismo tipo, y n un tipo entero o una enumeración; las operaciones permitidas y los resultados obtenidos con ellas son:
Operación Resultado Comentario pt1++ puntero Desplazamiento ascendente de 1 elemento pt1-- puntero Desplazamiento descendente de 1 elemento pt1 + n puntero Desplazamiento ascendente n elementos pt1 - n puntero Desplazamiento descendente n elementos pt1 - pt2 entero Distancia entre elementos pt1 == NULL booleano Siempre se puede comprobar la igualdad o desigualdad con NULL pt1 != NULL booleano pt1 <R> pt2 booleano <R> es una expresión relacional pt1 = pt2 puntero Asignación pt1 = void puntero genérico Asignación
NOTA: La comparación de punteros solo tiene sentido entre punteros a elementos de la misma matriz; en estas condiciones los operadores relacionales ( 4.9.12): ==, !=, <, >, <=, >=, funcionan correctamente.
Ejemplos:
editarN. Expresión Resultado 1. ip+10; Produce otro puntero; Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo: si *ip == &m[j] ), el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz, con lo que *(ip+10) == &m[j+10] 2. y = *ip+10; Añade 10 al objeto *ip (objeto referenciado por ip) y lo asigna a y 3. *ip += 1; Equivale a: *ip = *ip + 1. Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip. 4. ++*ip; Igual que el anterior: incrementa en 1 el valor del objeto referenciado por ip 5. ++ip; El resultado es otro puntero. Equivale a ip = ip+1, es decir, incrementa en 1 el valor del puntero, con lo que el nuevo puntero señala a otra posición (ver caso 1.) 6. ip++; Igual que el caso anterior. Incrementa en 1 el valor del puntero. 7. (*ip)++ Igual que el caso 4. Dado que el paréntesis tiene máxima precedencia y asocia de izquierda a derecha, incrementa en 1 el valor del objeto referenciado por ip. Observe que el paréntesis es necesario; sin él la expresión modifica la posición de memoria señalado por ip. Es decir, se realiza ip++;. Si ip es un puntero al elemento m[j] de una matriz, el resultado es un puntero al elemento m[j+1]. Después se tomaría la indirección, es decir, el resultado final sería el valor del elemento m[j+1].
Por tanto, la expresión *ip++ equivale a *(ip++)
8. *ip+1; El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip
Proyecto: Programación en C |
Anterior: Fundamentos de C - Lección 4 — Fundamentos de C - Lección 5 — Siguiente: Fundamentos de C - Lección 6 |