1Daniel Finol
TÉCNICAS DE PROGRAMACIÓN
Lenguaje C - 2
Daniel Finol
Daniel Finol
TIPOS OPERADORES Y EXPRESIONES
Capítulo 2 de K y R
Daniel Finol
Nombres de variables y constantes Nombres de variables y constantes:
Letras (mayúsculas o minúsculas; A != a). Dígitos decimales. Subrayado (‘_’).
Primer carácter: No puede ser dígito. No debe ser ‘_’.
Tradición (convención): minúsculas para los nombres de variables. MAYÚSCULAS SOSTENIDAS para las constantes
simbólicas.
Daniel Finol
Nombres de variables y constantes
No usar palabras claves.
Nombres Documentación.
Externas: Sólo hay garantía primeros 31 caracteres. Ahora (C99) sí se garantiza A != a.
Daniel Finol
Tipos de variable
• El tipo de una variable indica:– el conjunto de valores que puede tener,– las operaciones que se pueden realizar sobre ella.
• Tipos básicos:
char Un byte; guarda un carácter.
int Un entero.
float Punto flotante; precisión sencilla (single).
double Punto flotante; precisión doble.
Daniel Finol
Tamaños y Modificadores de tipos
Modificadores (o calificadores) para int: short int >= 16 bits.
long int >= 32 bits.
short <= int <= long.
int es del tamaño “normal” de los enteros de la máquina.
La palabra int puede omitirse de la declaración.
Daniel Finol
Tamaños y Modificadores de tipos
Modificadores signed y unsigned:
Se aplican a int y char.
unsigned: cero o positivo.
unsigned char = [0 , 255]
signed char = [-128 , 127] (complemento a 2)
long double: p. flotante precisión extendida.
Daniel Finol
Constantes
Una constante entera que tenga el sufijo u o U se toma como unsigned.
Una constante entera es long si:
No cabe en un int.
Está terminada por L o l (ele).
Daniel Finol
Constantes
Una constante es de punto flotante si: Contiene un punto decimal: 1.234. Está en notación científica: 1e-2.
Una constante de punto flotante se toma como double excepto: Si termina en f o F; se toma como float. Si termina en l (ele) o L; se toma como long double.
Daniel Finol
Constantes
Constantes de carácter: 'A', '\0'.
Expresiones constantes. Se calculan en tiempo de compilación. Ej.:
#define MAXLINE 1000 char line[MAXLINE+1];
Daniel Finol
Constantes
"Constante de cadena", "". Las comillas no forman parte de la cadena, sólo la
delimitan.
Una cadena es un arreglo de caracteres.
La representación interna de una constante de cadena tiene un carácter nulo al final.
El espacio de almacenamiento requerido es uno más que el número de caracteres entre comillas.
Daniel Finol
Longitud de una cadena.
Para saber la longitud de una cadena hay que recorrerla toda:
int strlen(char s[]){
int i;
i = 0;while (s[i] != '\0')
++i;return i;
}
strlen está en <string.h>
Daniel Finol
'x' != "x";
'x' es un pequeño entero (char).
"x" es un arreglo de dos caracteres.
Daniel Finol
Secuencias de escape
\a alerta (campana) \\ backslash
\b backspace \? question mark
\f formfeed \' single quote
\n nueva línea \" double quote
\r retorno de carro \ooo octal number
\t horizontal tab \xhh hexadecimal number
\v vertical tab
Daniel Finol
Enumeraciones
enum Crea una lista de constantes auto enumeradas:
enum booleana {FALSO, VERDAD};
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t', NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC };
Daniel Finol
Enumeraciones
Se pueden declarar variables de tipo enum pero el compilador no chequea qué se le asigna.
Sirve más bien como ‘documentación-en-código’.
Daniel Finol
Declaraciones
Una declaración especifica un tipo de dato seguido de una o más variables de ese tipo. Si hay más de una variable, estas se separan por
comas. Termina en punto y coma.
Una variable puede ser inicializada en su declaración: int i = 0;
Daniel Finol
Inicialización Variables No-Automáticas
Si no es automática (externas y estáticas):
se inicializa una sola vez al (antes del) inicio del programa.
se debe inicializar con una expresión constante.
se inicializan a cero por defecto (atención: sólo variables no automáticas).
Daniel Finol
Inicialización Variables Automáticas
Si es automática (locales no estáticas):
la inicialización se ejecuta cada vez que se entra al bloque donde se encuentra (si se inicializa).
puede ser inicializada con cualquier expresión.
si no es inicializada contiene valores indefinidos: basura.
Daniel Finol
Declaraciones: const
El calificador const puede aplicarse a la declaración de una variable para especificar que su valor no será cambiado:
const double e = 2.71828182845905;
const char msg[] = "warning: ";
int strlen(const char[]);
Los elementos de los arreglos no serán cambiados
Daniel Finol
Operadores aritméticos
Operadores aritméticos binarios: +, -, *, / y %.
La división entera trunca: 4 / 3 == 1 3 / 4 == 0
x % y es el residuo de x entre y: 4 % 3 == 1
Daniel Finol
Operadores aritméticos
El módulo es cero cuando x es múltiplo de y. Ej:
if((year % 4 == 0 && year % 100 != 0) || year % 400==0)
printf("%d es año bisiesto\n", year);
else
printf("%d no es bisiesto\n", year);
Daniel Finol
Operadores Aritméticos
Con operandos negativos no se especificaba:Dirección de truncamiento de /.Signo del resultado de %.
Ahora (C99) sí:Dirección de truncamiento: cero.Tiene signo y satisface la ecuación:
(a/b)*b + a%b == a
-22 / 7 = -4-22 % 7 =
-22 / 7 = -3 -22 % 7 = -1
Daniel Finol
Operadores relacionales y lógicos
Operadores relacionales: > < <= >=
tienen menor precedencia que los aritméticos:
i < lim – 1 se interpreta como i < (lim – 1).
Operadores de igualdad:== !=
Daniel Finol
Operadores relacionales y lógicos
Operadores lógicos:&& ||
&& tiene mayor precedencia que ||. Ambos son evaluados de izquierda a derecha
La evaluación se detiene tan pronto se conozca el resultado (verdadero o falso).
Daniel Finol
Operadores lógicos
for(i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
Tienen menor precedencia que los operadores relacionales.
Verificar si hay espacio para guardar el carácter antes de leerlo.
Daniel Finol
Operadores lógicos
for(i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
Leerlo antes de probar si es EOF o nueva línea.
Precedencia de != es mayor que la de asignación; se necesitan paréntesis en
(c=getchar()) != '\n'
Daniel Finol
El valor numérico de una expresión lógica y relacional es 1 si es verdadera y 0 de ser falsa.
Operador unario de negación !
if(!valid) if(valid == 0)
Daniel Finol
Conversiones de tipo
Si un operador tiene operandos de tipos distintos, éstos se convierten a un tipo común siguiendo ciertas reglas.
Las únicas conversiones automáticas son las que convierten un operando "pequeño" o "angosto" o uno más "grande" o "amplio" sin pérdida de información.
Daniel Finol
Conversiones de tipo
Ej.: de entero a punto flotante en f + i.
Operaciones que pueden perder información no son ilegales (no producen error).
Daniel Finol
Conversión de una cadena
Un char es un entero pequeño, de modo que se puede usar en expresiones aritméticas.
atoi convierte una cadena de dígitos a su equivalente en un valor entero:
int atoi(char s[]) {
¿?
}
Daniel Finol
Conversión de una cadena
Un char es un entero pequeño, de modo que se puede usar en expresiones aritméticas.
atoi convierte una cadena de dígitos a su equivalente en un valor entero:
int atoi(char s[]) { int i, n;
n = 0; for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i) n = 10 * n + (s[i] - '0'); return n; }
Daniel Finol
char a int
El estándar no especifica si las variables char tienen signo o no.
Cuando una variable char se convierte a int ¿es posible que produzca un número negativo?
Respuesta: depende de la implantación.
Portabilidad: se debe especificar unsigned o signed si se van a guardar datos que no son caracteres en una variable char.
Daniel Finol
Conversiones automáticas
En una operación binaria (que no sea de asignación):
se promueve la variable más "pequeña" al tipo de la más grande.
los char y short se promueven a int.
Daniel Finol
Conversiones automáticas
En una asignación se transforma el valor de la derecha al tipo de la variable de la izquierda.
int i;
char c;
...
i = c;
c = i;
int i;
char c;
...
c = i;
i = c;
Daniel Finol
casting
Se puede forzar explícitamente la conversión de tipo de cualquier expresión con el operador de cast:
(nuevo-tipo) expresión
Si usan funciones que no han sido declaradas se realiza una conversión por defecto de los argumentos que no necesariamente corresponde a los tipos de los parámetros de la función. Esto puede producir errores. Ej. sqrt.
Daniel Finol
casting – Números aleatorios unsigned long int next = 1;
int rand(void) {
next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; }
void srand(unsigned int seed) { next = seed; }
Daniel Finol
Operadores de incremento y decremento
++ y -- incrementa o disminuye en 1 la variable.
Prefijo (++x o --x): modifican x antes de su uso.
Posfijo (x++ o x--): modifican x luego de su uso.
n = 5;x = n++;
n = 5;x = ++n;
if (c == '\n') nl++;
if (c == '\n') ++nl;
Daniel Finol
Operador de incremento - ¿Qué hace esta función? void s(char s[], int c) { int i, j;
for (i = j = 0; s[i] != '\0'; i++) if (s[i] != c) s[j++] = s[i]; s[j] = '\0'; }____________________________________________________
if (s[i] != c) { s[j] = s[i]; j++; }
Daniel Finol
Operador de incremento - ¿Qué hace la función? void f(char s[], char t[]) { int i, j;
i = j = 0; while (s[i] != '\0') i++; while ((s[i++] = t[j++]) != '\0') ; }
Daniel Finol
Manejo de bits
• Los operadores para manejo de bits sólo pueden aplicarse a enteros (char, short, int y long):
& Y (AND) de bits
| O (OR) inclusivo de bits
^ O exclusivo (XOR) de bits
<< desplazamiento (shift) a la izquierda
>> desplazamiento (shift) a la derecha
~ complemento a uno (unario)
Daniel Finol
Operadores de bits
El operador Y de bits (&) sirve para enmascarar bits: n = n & 0177
1 & 2 == ?
1 && 2 == ?
Daniel Finol
El operador O Inclusivo (|) puede encender bits:n = n | SET_ON
1 | 2 == ?
1 || 2 == ?
Daniel Finol
Operadores de bits
El operador O Exclusivo (^) pone uno en cada posición donde sus operandos tienen bits distintos y cero donde no.
1 ^ 2 == ?
Daniel Finol
Operadores de bits
<< desplazamiento a la izquierda
llena con ceros
5 << 3 == ?
Daniel Finol
Operadores de bits
<< desplazamiento a la izquierda llena con ceros
5 << 3 …000101 << 3 …001010 == ? …010100 == ? …101000 == ?
Daniel Finol
Operadores de bits
<< desplazamiento a la izquierda
llena con ceros
x << n == x*2n
Daniel Finol
Operadores de bits
>> desplazamiento a la derecha.
unsigned >> llena con ceros.
signed >> depende de la implantación.
Daniel Finol
Operadores de bits
>> desplazamiento a la derecha. 5 >> 1 == ?
40 >> 3 == ?
5 >> 3 == ?
Daniel Finol
Operadores de bits
~ complemento
Queremos borrar los 6 bits más bajos de x. ¿Cómo lo hacemos?
Daniel Finol
Operadores de bits
~ complemento
x = x & ~077
independiente del tamaño de x
Daniel Finol
Operadores de bits -- getbits
unsigned getbits(unsigned x, int p, int n) { return (x >> (p+1-n)) & ~(~0 << n); }
Daniel Finol
Operadores de asignación
Las asignaciones donde el operando de la izquierda se repite inmediatamente a la derecha del ‘=‘ pueden abreviarse:
i = i + 2 i += 2
i += 2 (“incrementar i en 2”)
se lee más fácil que:
i = i + 2 (“tomar i sumarle 2 y poner el resultado en i”)
Daniel Finol
Operadores de asignación
Hay operadores de asignación para:
+ - * / % << >> & ^ |
expresión1 = (expresión1)op (expresión2)
expresión1 op= expresión2
x *= y + 1 x = x * (y + 1)
excepto que expresión1 se evalúa una sola vez
Daniel Finol
Una ventaja de los operadores de asignación
yyval[yypv[p3+p4] + yypv[p1]] = yyval[yypv[p3+p4] + yypv[p1]] + 2
yyval[yypv[p3+p4] + yypv[p1]] += 2
Daniel Finol
Operadores de asignación – Conteo de bits
int bitcount(unsigned x) { ¿? }
Daniel Finol
Operadores de asignación – Conteo de bits
int bitcount(unsigned x) { int b;
for (b = 0; x != 0; x >>= 1) if (x & 01) b++; return b; } x es sin-signo para asegurar que no hay extensión de signo
Daniel Finol
Ejercicio
• ¿Qué efecto tiene la siguiente expresión en x?
x &= (x-1)
• Use esto para escribir una versión más rápida de bitcount
Daniel Finol
Expresiones condicionales ?:
expr1 ? expr2 : expr3
z = (a > b) ? a : b;
Tipo: si f es float y n int:
(n > 0) ? f : n es float.
Daniel Finol
Expresiones condicionales ?:
for (i = 0; i < n; i++)
printf("%6d%c",a[i], (i%10==9 || i==n-1) ? '\n' : ' ');
________________________________________________________
printf("Hay %d elemento%s.\n", n, n==1 ? "" : "s");
Daniel Finol
Precedencia
Operadores Asociatividad
() [] -> . izquierda a derecha
! ~ ++ -- + - * (type) sizeof derecha a izquierda
* / % izquierda a derecha
+ - izquierda a derecha
<< >> izquierda a derecha
< <= > >= izquierda a derecha
== != izquierda a derecha
& izquierda a derecha
^ izquierda a derecha
| izquierda a derecha
&& izquierda a derecha
|| izquierda a derecha
?: derecha a izquierda
= += -= *= /= %= &= ^= |= <<= >>=
derecha a izquierda
, izquierda a derecha
if(x & MASK == 0)
Daniel Finol
Precedencia
Para la mayoría de los operadores no está definido el orden de evaluación de sus operandos.
x = f() + g()
Excepciones: &&, ||, ?:, y ','
Daniel Finol
Precedencia
El orden de evaluación de los argumentos tampoco está definido:
/* MALO */ printf("%d %d\n", ++n, power(2, n));
Es decir, la coma que separa los argumentos de una función no es el operador coma.
Daniel Finol
Efectos colaterales ≈ Daños colaterales
Las llamadas a funciones, asignaciones anidadas y operadores de incremento y decremento producen "efectos colaterales“:
Alguna variable se modifica como efecto de la evaluación de una expresión.
Daniel Finol
Efectos colaterales ≈ Daños colaterales
s[i] = i++; ¿?
Escribir código que dependa del orden de evaluación es una mala práctica. (No es transportable)
Daniel Finol
Ejercicio – set_bit
Hacer una función que encienda o apague el n-ésimo bit de un entero.
int set_bit(int x, int n, int b)
Daniel Finol
EjercicioDeben crear un programa que lea de la entrada
estándar una secuencia de 1’s y 0’s y usarlos para llenar los bits un arreglo de char's
De manera que los primeros ocho 1's y 0's representen los bits del primer char del arreglo los siguientes los del siguiente char, etc.
La entrada puede estar dividida en líneas, de encontrarse un caracter nueva línea antes de haber leído los ocho bits del char actual los leídos hasta ese momento se tomarán como los bits menos significativos y los restantes se tomarán por ceros.
Después de leer toda la entrada deben imprimirse los bits de los char's leídos
Daniel Finol
Ejercicio
¿Cómo intercambiar dos variables sin usar variables o almacenamiento temporal?
Top Related