Resumen de Lenguaje C

Anuncio
Resumen de Sintaxis en C
1
Tipos, operadores y expresiones
Identificadores: Formados por letras, números y '_'. Los primeros 31 caracteres son significativos
(dependiente del compilador). Las mayúsculas y las minúsculas se distinguen (case sensitive). Las palabras
reservadas van en minúsculas
Tipos de datos:
Simples:
caracter:
char
->
1 byte
entero:
int
Normalmente refleja el tamaño de los enteros en la máquina host
short [int]
->
16 bits
long [int]
->
32 bits
real:
float
Los tamaños son dependientes de la implementación.
double
->
Precisión doble
long double
->
Precisión extendida
Complejos:
enumeraciones, arreglos, estructuras y uniones.
Declaraciones: Todas las variables deben declararse antes de usarse. Una declaración especifica un
tipo seguido de una lista no vacía de variables de ese tipo (separadas por comas).
float f1, f2;
Ejemplo:
int i = 1;
/* Inicializada al definirla */
Enumeraciones:
enum <nombre> {<enumeradores>}
enum boolean {false, true} false vale 0, (por defecto) y true vale 1
Ejemplos:
enum semana {Lun=1, Mar, Mie, Jue, Vie, Sab, Dom}
enum constantes {nl = '\n', cr = '\r'}
Arreglos:
Ejemplo:
<tipo> <nombre>[<#elem>].
char nombre[30];
arreglo de 30 caracteres- posiciones del 0 al 29.
Estructuras: struct <nombre> {declaración de los elementos}
struct círculo{
Ejemplo:
int radio;
int x,y; /* Coordenadas del centro */ } circ;
Acceso a los campos a través del operador de proyección '.'
circ.radio, circ.x, circ.y
Declaración de nuevos tipos:
typedef <declaración del que será sinónimo> <nuevo nombre>
typedef struct s_emp{
Ejemplo:
char nombre[30];
float sueldo;
int dpto; } empleado;
Constantes:
#define <nombre> <valor>
El #define es una directiva para el compilador que indica que se reemplazará <nombre> por <valor> en
el texto.
Ejemplos:
Operadores:
#define MAX_ELEMS 50
Asignación: =
Casting: operador que obliga a la conversión a un tipo dado:
f = (float) i;
/* i no se ve alterado */
Conversiones de tipo: f = i; /* no hace falta el cast */
i = f; /* se trunca f */
Aritméticos: +, -, *, /, %, ++, - -, +=, -=.
Hablar de la diferencia entre el pre y el post-decremento i++ vs. ++i
Relacionales: >, >=, <, <=, ==, !=.
Lógicos: &&, ||, &, |, !.
Ejemplos:
2
a && b -> a y b
a || b
-> a ó b
!p
-> no p
Estructuras de control
Instrucciones: Son expresiones seguidas por punto y coma (;). Las llaves son utilizadas para agrupar
instrucciones en bloques, que sintácticamente equivalen a una instrucción.
Condicionales:
if_else: if (cond) inst1
[else inst2]
switch: switch (exp)
{ case val1: inst1
...
case valn: instn
[default: instn+1]
}
Para romper el flujo de control dentro del bloque insti se utiliza la instrucción break.
Ciclos:
while
while (exp)
inst;
for
do_while:
3
for (exp1; exp2; exp3)
inst;
do
inst;
while (cond);
Funciones
En C no existen procedimientos, sólo hay funciones. Los procedimientos pueden ser simulados por medio de
funciones que no retornan ningún valor.
<tipo ret> <nombre>(<parámetros>)
{ declaraciones;
instrucciones;
}
donde
<tipo ret> es el tipo de valor que devuelve la función (por defecto int). Para indicar que no se devuelve
nada se coloca void.
<parámetros> es una lista de elementos: <tipo nombre>, separados por comas.
Para devolver el valor se tiene la instrucción return <exp>. No se pueden devolver estructuras
complejas.
Pasaje de parámetros: El pasaje de parámetros es siempre por valor. Si se desea simular un pasaje de
parámetros por referencia se debe pasar un apuntador por cada variable cuyo valor se desea modificar. Lo que
se pasará como parámetro en este caso será la variable apuntador, i.e., la que contiene la dirección de la
variable a modificar.
Apuntadores:
Ejemplo:
Los apuntadores se declaran así:<tipo_de_lo _apuntado> *<nombre_ap>;
char *s,c;
/* s es un apuntador a un caracter */
se puede realizar la siguiente asignación:
c = *s; /* c <- contenido de la dir. indicada por s */
El valor NULL se encuentra definido en un a librería (stdio) y vale 0
La dirección de una variable se obtiene aplicando a ésta el operador &. Supongamos que a es char. Siguiendo
s=&a; es una asignación válida. Si se desea pasar por referencia la variable a en la
con el ejemplo:
función f, la llamada se hace así: f(&a) y f debe recibirlo así:
<tipo_ret> f(char *ap) ...
Aritmética de apuntadores
Cualquier operación que puede ser realizada sobre los índices de un arreglo
puede realizarse con apuntadores.
int a[5], x, *ap;
Ejemplo:
ap= a; es equivalente a
ap=&a[0];
Se coloca ap a apuntar al primer elemento del arreglo a. La equivalencia surge pues el nombre del
arreglo es un sinónimo para la dirección del primer elemento.
x=*ap; es equivalente a
x=a[0];
Si ap apunta a a[0] => ap + i apunta a a[i].
Esta aritmética es válida para un apuntador a cualquier cosa ya que se toma como unidad el tamaño de
lo apuntado, i. e., ap + i implica que a ap se e suma i veces el tamaño del entero para obtener la posición del
elemento buscado.
Los strings son arreglos de caracteres. Los strings se copian caracter por caracter teniendo apuntadores
a cada una de las estructuras en las que se trabaja e "incrementando" el apuntador.
La marca de fin de string es '\0'.
Apuntadores a funciones: Son tratadas como los arreglos (no se necesita el & para obtener su dirección, ésta la
indica su nombre).
Palabra reservada void: void implica que falta el valor. Por ejemplo: si una función no retorna ningún valor ni
recibe ningún argumento, lucirá así:
void f(void)
void * : Apuntador a cualquier cosa.
Ejercicio 1: - Pregunta 1 del problemario - Verificar Declaraciones y estudiar alcance de variables.
/* archivo p1 */
int k,x;
void r1(int a,int b)
{
int i;
i=0;
a=2*b;
r3(i);
printf("%d %d", x,k);
}
main()
{
k=1;
x=2;
r1(k,x);
printf("%d %d",x,k);
}
ALCANCE
var
k (global)
x (global)
a (local r1)
b (local r1)
i (local r1)
i (local r2)
a (local r3)
x (local r3)
y (local r3)
/* archivo p2 */
int r2(int i)
{
i=i+3;
if (k <= 2)
printf("%d %d",i,k);
return(i+k);
}
void r3(int a)
{
int x,y;
a=a+k;
x=r2(a);
y=r2(2*a);
printf("%d %d",x,y);
k=x+y
}
alcance
p1 (r1 y main)
p1 (r1 y main)
r1
r1
r1
r2
r3
r3
r3
El alcance de k no le permite ser usado en el archivo p2. Por lo tanto k debe ser declarada como extern para
poder tener alcance sobre r2 y r3 que la usan.
La corrida produce los siguientes resultados:
Pila de invocación
espacio global
k=1, 11
x=2
main
r1 (invocación desde main con parámetros k,x)
a=1,4
b=2
i=0
r3 (invocación desde r1 con parámetro i)
a=0, 1
x=5
y=6
r2 (invocación desde r3 con parámetro a)
i=1,4
r2 (invocación desde r3 con parámetro 2*a)
i=2,5
Imprime
4 1 5 1 5 6 2 11 2 11
APUNTADORES Y ARREGLOS
2.- Encuentre el error en cada uno de los segmentos de programas siguientes. Suponga:
int *zPtr;
int *aPtr = NULL;
void *sPtr = NULL;
int number,i;
int z[5] = {1,2,3,4,5};
sPtr=z;
a) ++z;
Esta operación no es válida pues el nombre de un arreglo es un apuntandor constante (no puede
modificarse)
b) number = zPtr; /* uso del apuntador para obtener el primer valor del arreglo */
Debe asignarse a zPtr la dirección del arreglo y luego tomar el contenido del apuntador.
zPtr = z;
number = zPtr;
c) number = *zPtr[2]; /* asigna el valor 3 a number*/
No hace falta el operador *. La manera correcta es
number = zPtr[2];
d) number = *sPtr;
/* asigna el valor apuntado por sPtr a number */
Es incorrecta pues sPtr no está apuntado a ningún objeto
e) for (i=0;i<=5;i++) /* imprime el arreglo z */
printf(“%d”,zPtr[i]);
Es correcto siempre que se haya asignado a zPtr la dirección del arreglo y la operación condicional del for
sea estrictamente menor.
3.- Para cada uno de los siguientes enunciados, escriba el trozo de código correspondiente. Suponga que se
han declarado las variables num1 y num2 de tipo flotante.
a) Declare la variable fPtr como apuntador a un flotante
float *fPtr;
b) Asigne la dirección de la variable num1 a la variable fPtr
fPtr=&num1;
c) Imprima el valor del objeto señalado por fPtr
printf("%f",*fPtr);
d) Asigne el valor del objeto señalado por fPtr a la variable num2
num2=*fPtr;
e) Imprima el valor de num2
printf("%f",num2);
f) Imprima la dirección de num1. Utilice el especificador de conversión %p
printf("%p",&num1);
g) Imprima la dirección almacenada en fPtr utilizando %p ¿Es el valor impreso el mismo de la dirección de
num1?
printf("%p",fPtr);
5.- Para el siguiente programa, realice la corrida observando lo que ocurre en la pila de invocación. Modifique el programa
para que los parámetros de la función sean todos por referencia. Realice la corrida con el programa modificado:
void pr(int x,int y,int z);
void pr(int x,int y,int z);
{
main() {
int a=5,b=8,c=3;
pr(a,b,c);
printf("%d%d%d",a,b,c);
pr(b,c,a);
printf("%d%d%d",a,b,c);
pr(c,b,a);
printf("%d%d%d",a,b,c);
}
z=x+y+z;
}
Si se hace la corrida con los parámetros por valor el resultado siempre es el mismo. Por lo que imprime tres
veces los valores iniciales de a,b,c.
Al hace la corrida con todos los parámetros por referencia hay que tener cuidado con la asignación a z que
cambia a *z=*x+*y+*z. También cambia la declaración de los parámetros formales y la invocación.
Descargar