Subsecciones

2. Principios de C

En este capítulo se ofrece una breve historia del desarrollo del lenguaje C y se consideran también sus características.

En el resto del capítulo se ven los aspectos básicos de los programas de C, tales como su estructura, la declaración de variables, tipos de datos y operadores.

2.1 Orígenes del C

El proceso de desarrollo del lenguaje C se origina con la creación de un lenguaje llamado BCPL, que fue desarrollado por Martin Richards. El BCPL tuvo influencia en un lenguaje llamado B, el cual se usó en 1970 y fue inventado por Ken Thompson y que permitió el desarrollo de C en 1971, el cual lo inventó e implementó Dennis Ritchie. Para 1973 el sistema operativo UNIX estaba casi totalmente escrito en C.

Durante muchos años el estándar para C fue la versión 5 del sistema operativo UNIX, documentada en ``The C Programming Language'' escrito por Brian W. Kernighan and Dennis M. Ritchie in 1978 comúnmente referido como K&R.

Posteriormente se hicieron varias implementaciones las cuales mostraban las siguientes tendencias:

Esto originó que en el verano de 1983 se estableciera un comité para resolver estas discrepancias, el cual empezó a trabajar en un estándar ANSI C, la cual fue completada en 1988.

2.2 Características de C

Algunas de las características más importantes que definen el lenguaje y que han permitido que sea tan popular, como lenguaje de programación son:

Las diversas razones por la cual se ha convertido en un lenguaje de uso profesional son:

Un punto en contra es que tiene una detección pobre de errores, lo cual en ocasiones es problemático para los principiantes.

2.3 Estructura de un programa en C

Un programa de C tiene básicamente la siguiente forma:

Para un programa se debe tener una función main().

Una función tiene la forma:

tipo nombre_de_la_funcion (parámetros)
{

      variables locales
              
      sentencias de C
              
}

Si la definición del tipo es omitida, C asume que la función regresa un tipo entero. Nota: Lo anterior puede ser una fuente de problemas en un programa.

A continuación se muestra un primer programa:

/* Programa ejemplo */ 
              
main()
{
              
   printf( "Me gusta C\n" );
   exit (0);
              
}

NOTAS:

En caso de que se hubiera llamado a la función printf de la siguiente forma:

printf(".\n.1\n..2\n...3\n");

La salida tendría la siguiente forma:

.1
..2
...3

2.4 Variables

C tiene los siguientes tipos de datos simples:

Tabla 2.1: Tipos de C
Tipo Tamaño (bytes) Límite inferior Límite superior
char 1 -- --
unsigned char 1 $0$ $255$
short int 2 $-32768$ $+32767$
unsigned short int 2 $0$ $65536$
(long) int 4 $-2^{31}$ $+2^{31}-1$
float 4 $-3.2 \times 10^{\pm38} $ $+3.2 \times 10^{\pm38} $
double 8 $-1.7 \times 10^{\pm308} $ $+1.7 \times 10^{\pm308} $


Los tipos de datos básicos tiene varios modificadores que les preceden. Se usa un modificador para alterar el significado de un tipo base para que encaje con las diversas necesidades o situaciones. Los modificadores son: signed, unsigned, long y short.

En los sistemas UNIX todos los tipos int son long int, a menos que se especifique explícitamente short int.

Nota: no hay un tipo booleano en C -- se deberá usar char, int o aún mejor unsigned char.

signed, unsigned, long y short pueden ser usados con los tipos char e int. Aunque es permitido el uso de signed en enteros, es redundante porque la declaración de entero por defecto asume un número con signo.

Para declarar una variable en C, se debe seguir el siguiente formato:

tipo lista_variables;

tipo es un tipo válido de C y lista_variables puede consistir en uno o más indentificadores separados por una coma. Un identificador debe comenzar con una letra o un guión bajo.

Ejemplo:

int i, j, k;
float x,y,z;
char ch;

2.4.1 Definición de variables globales

Una varible global se declara fuera de todas las funciones, incluyendo a la función main(). Una variable global puede ser utilizada en cualquier parte del programa.

Por ejemplo:

short numero, suma;
int numerogr, sumagr;
char letra;

main()
{
...
}

Es también posible preinicializar variables globales usando el operador de asignación =, por ejemplo:

float suma= 0.0;
int sumagr= 0;
char letra= 'A';

main()
{
...
}

Que es lo mismo que:

float suma;
int sumagr;
char letra;

main()
{
    suma  = 0.0;
    sumagr= 0;
    letra = 'A';

...
}

Dentro de C también se permite la asignación múltiple usando el operador =, por ejemplo:

a = b = c = d = 3;

...que es lo mismo, pero más eficiente que:

a = 3;
b = 3;
c = 3;
d = 3;

La asignación múltiple se puede llevar a cabo, si todos los tipos de las variables son iguales.

Se pueden redefinir los tipos de C usando typedef. Como un ejemplo de un simple uso se considera como se crean dos nuevos tipos real y letra. Estos nuevos tipos pueden ser usados de igual forma como los tipos predefinidos de C.

typedef float real;
typedef char letra;

/* Declaracion de variables usando el nuevo tipo */
real suma=0.0;
letra sig_letra;

2.4.2 Lectura y escritura de variables

El lenguaje C usa salida formateada. La función printf tiene un caracter especial para formatear (%) -- un caracter enseguida define un cierto tipo de formato para una variable.

%c caracteres
%s cadena de aracteres
%d enteros
%f flotantes

Por ejemplo:

printf("%c %d %f",ch,i,x);

La sentencia de formato se encierra entre " ", y enseguida las variables. Asegurarse que el orden de formateo y los tipos de datos de las variables coincidan.

scanf() es la función para entrar valores a variables. Su formato es similar a printf. Por ejemplo:

scanf("%c %d %f %s",&ch, &i, &x, cad);

Observar que se antepone & a los nombres de las varibles, excepto a la cadena de caracteres. En el capítulo 8 que trata sobre apuntadores se revisará más a fondo el uso de este operador.

2.5 Constantes

ANSI C permite declarar constantes. Cuando se declara una constante es un poco parecido a declarar una variable, excepto que el valor no puede ser cambiado.

La palabra clave const se usa para declarar una constante, como se muestra a continuación:

const a = 1;
int a = 2;

Notas:

La directiva del preprocesador #define es un método más flexible para definir constantes en un programa.

Frecuentemente se ve la declaración const en los parámetros de la función. Lo anterior simplemente indica que la función no cambiara el valor del parámetro. Por ejemplo, la siguiente función usa este concepto:

char *strcpy(char *dest, const char *orig);

El segundo argumento orig es una cadena de C que no será alterada, cuando se use la función de la biblioteca para copiar cadenas.

2.6 Operadores Aritméticos

Lo mismo que en otros lenguajes de programación, en C se tienen los operadores aritméticos más usuales (+ suma, - resta, * multiplicación, / división y % módulo).

El operador de asignación es =, por ejemplo: i=4; ch='y';

Incremento ++ y decremento -- unario. Los cuales son más eficientes que las respectivas asignaciones. Por ejemplo: x++ es más rápido que x=x+1.

Los operadores ++ y -- pueden ser prefijos o postfijos. Cuando son prefijos, el valor es calculado antes de que la expresión sea evaluada, y cuando es postfijo el valor es calculado después que la expresión es evaluada.

En el siguiente ejemplo, ++z es prefijo y -- es postfijo:

int x,y,z;

main()
{
    x=( ( ++z ) - ( y-- ) ) % 100;
}

Que es equivalente a:

int x,y,z;

main()
{
    z++;
    x = ( z-y ) % 100;
    y--;
}

El operador % (módulo o residuo) solamente trabaja con enteros, aunque existe una función para flotantes (15.1 fmod() ) de la biblioteca matemática.

El operador división / es para división entera y flotantes. Por lo tanto hay que tener cuidado. El resultado de x = 3 / 2; es uno, aún si x es declarado como float. La regla es: si ambos argumentos en una división son enteros, entoces el resultado es entero. Si se desea obtener la división con la fracción, entonces escribirlo como: x = 3.0 / 2; o x = 3 / 2.0 y aún mejor x = 3.0 / 2.0.

Por otra parte, existe una forma más corta para expresar cálculos en C. Por ejemplo, si se tienen expresiones como: i = i + 3; o x = x * (y + 2); , pueden ser reescritas como:

$expr_1 \mbox{ oper } = expr_2$

Lo cual es equivalente, pero menos eficiente que:

$expr_1 = expr_1 \mbox{ oper } expr_2$

Por lo que podemos reescribir las expresiones anteriores como: i += 3; y x *= y + 2; respectivamente.

2.7 Operadores de Comparación

El operador para probar la igualdad es ==, por lo que se deberá tener cuidado de no escribir accidentalmente sólo =, ya que:

if ( i = j ) ...

Es una sentencia legal de C (sintácticamente hablando aunque el compilador avisa cuando se emplea), la cual copia el valor de ``j'' en ``i'', lo cual será interpretado como VERDADERO, si j es diferente de cero.

Diferente es !=, otros operadores son: < menor que, > mayor que, <= menor que o igual a y >= (mayor que o igual a).

2.8 Operadores lógicos

Los operadores lógicos son usualmente usados con sentencias condicionales o relacionales, los operadores báscios lógicos son:

&& Y lógico, || O lógico y ! negación.

2.9 Orden de precedencia

Es necesario ser cuidadosos con el significado de expresiones tales como a + b * c, dependiendo de lo que se desee hacer

(a + b) * c
o
a + (b * c)

Todos los operadores tienen una prioridad, los operadores de mayor prioridad son evaluados antes que los que tienen menor prioridad. Los operadores que tienen la misma prioridad son evaluados de izquierda a derecha, por lo que:

a - b - c
es evaluado como
(a - b) - c

Prioridad Operador(es)
Más alta ( ) [ ] ->
  ! ~ ++ -- - (tipo) * & sizeof
  * / %
  + -
  << >>
  < <= > >=
  == !=
  &
  ^
  |
  &&
  ||
  ?
  = += -= *= /=
Más baja ,

De acuerdo a lo anterior, la siguiente expresión:

a < 10 && 2 * b < c

Es interpretada como:

(a < 10) && ( (2 * b) < c )

y

a =
     b =
            10 / 5
                    + 2;

como

a =
     ( b =
            ( 10 / 5 )
                        + 2 );

2.10 Ejercicios

Escribir programas en C para hacer las siguientes tareas:

  1. Leer la entrada de dos números y mostrar el doble producto del primero menos la mitad del segundo.
  2. Lea y escriba su nombre, apellido paterno, apellido materno y matricula en un formato adecuado.
  3. Escribir un programa para leer un ``flotante'' que representa un número de grados Celsius, e imprime como un ``flotante'' la temperatura equivalente en grados Fahrenheit. La salida puede ser de la siguiente forma: 100.0 grados Celsius son 212.0 grados Fahrenheit.
  4. Escribir un programa para imprimir varias veces el ejercicio 2. Puede usar varias instrucciones printf, con un caracter de nueva línea en cada una, o una instrucción con varios caracteres nueva línea en la cadena de formateo.
  5. Escribir un programa que lea el radio de un círculo como un número flotante y muestre el área y el perímetro del círculo.

  6. Dados ciertos centímetros como entrada de tipo flotante, imprimir su equivalencia a pies (enteros) y pulgadas (flotante, 1 decimal), dando las pulgadas con una precisión de un lugar decimal Suponer 2.54 centímetros por pulgada, y 12 pulgadas por pie.
    Si la entrada es 333.3, el formato de la salida deberá ser:
    333.3 centímetros son 10 pies 11.2 pulgadas.