Monografias.com > Computación > Programación
Descargar Imprimir Comentar Ver trabajos relacionados

Lenguaje C ( programación)




Enviado por oscarritch



    1. Tipos operadores y
      expresiones
    2. Operador
      asociatividad
    3. Control de
      flujo
    4. Funciones y la estructura del
      programa
    5. Entrada y
      salida

    Cadenas de
    caracteres.
    Tienen un caracter nulo al
    final ('').
    Ej. "hellon" -> h e l l o n
    Tipos de variables
    Entre
    los tipos de variables se
    cuentan:
    Automáticas
    Externas
    Las variables automáticas…
    – aparecen y desaparecen con la llamada de la función.
    Las variables externas…
    – se declaran globalmente: extern int max;
    – se definen fuera de las funciones: int
    max;
    – se declaran dentro de las funciones: extern int max;

    TIPOS
    OPERADORES Y EXPRESIONES

    Nombres de las
    variables
    Letra (Letra o Dígito)* -> 31
    caracteres
    Las mayúsculas son diferentes de las minúsculas
    Es práctica común de C, denotar con
    – MAYUSCULAS las constantes
    – minúsculas las variables
    Tipos
    char
    int -> (CALIFICADORES: short, long, unsigned)
    float
    double
    Constantes
    Simbólicas (Preprocesamiento)
    Ej. #define PI 3.14159265359

    #define MAXLINE 1000
    char line [MAXLINE+1]

    #define FORMFEED '14'
    Variables constantes:
    Ej. const float pi=3.14159265359;
    Alfanuméricas:
    Se evalúan en tiempo de
    compilación, no de ejecución.
    Ejs. 3.14159265359
    123.456e-7
    0.12E3
    '0' -> ASCII 48, EBCDIC
    240

    Declaraciones:
    Se pueden declarar varias variables en
    pocos renglones:
    int lower,upper,step;
    char c, line[1000];
    También se pueden escribir más explicitamente, para
    agregar comentarios:
    int lower; /* algunos comentarios */
    int upper;
    int step;
    char c;
    char line[1000];
    Inicialización de variables:
    char
    backslash='\';
    int i=0;
    Operadores aritméticos:
    + – * /
    %(módulo)
    Ej. (uso del módulo)
    if (year%4==0 && year%100!=0 || year%400==0)
    es un año bisiesto;
    else
    no lo es;
    Operadores relacionales y lógicos:
    > >=
    <= < == !=
    El operador que convierte en 0 algo distinto de 0, y en 1, el
    cero, es !. Ej.
    if (!inword)
    if (inword==0)
    Conversiones de Tipos
    Se hacen conversiones
    automáticas cuando tiene sentido. Ej.
    float + int -> float
    "char" e "int" se manejan indiscrimidamente. Ej.
    int atoi(char s[]) /* convierte s a int */
    {
    int i,n;
    n=0;
    for (i=0; s[i]>='0' && s[i]<='9';++i)
    n=10*n+s[i]-'0';
    return (n);
    }
    Conversión coaccionada "cast"
    Se puede forzar
    la conversión de un tipo en otro. El formato es:
    (nombre-de-tipo) expresión
    por ejemplo:
    sqrt( (double) n)
    Operadores de incremento y decremento
    si n=5, entonces
    x=n++; -> x=5 n=6
    x=++n; -> x=6 n=6
    Operadores lógicos para manejo de bits:
    &
    AND lógico
    | OR lógico
    ^ XOR lógico
    << desplazamiento a la izquierda
    >> desplazamiento a la derecha
    ~ complemento a uno (unario)

    Ejs
    c = n & '77';
    x = x | MASK;
    x = x & ~'77';

    Ej. Función para tomar n bits a partir de la
    posición p

    getbits(unsigned int x, p, n)
    {

    return ((x>>(p+1-n)) & ~(~0 <<
    n));

    }
    Nota: (~0 << n) es 11..100..0
    con n ceros a la derecha
    ~(~0 << n) es 00..011..1 con n unos a la derecha

    Operadores y expresiones de asignación

    La expresión
    e1 op= e2
    es idéntico a
    e1 = e1 op e2
    donde "op" es un operador como
    {],-,*,/,%,<<,>>,&,^,|}
    Por ejemplo: i=i+2; es idÚntico a i+=2;
    Expresiones condicionales
    Tienen el siguiente
    formato
    e1 ? e2 : e3;
    si e1 es verdadero se evalúa e2, si e1 es falso, se
    evalúa e3.
    z=(a>b) ? a : b; /* z=max(a,b) */
    Precedencia y orden de evaluación

    OPERADOR
    ASOCIATIVIDAD
    () [] -> . ->
    ! ~ ++ — – (tipo) * & sizeof <-
    * / % ->
    + – ->
    << >> ->
    < <= > >= ->
    == != ->
    & ->
    ^ ->
    | ->
    && ->
    || ->
    ? : <-
    = += -= etc <-
    0 ->
    ASOCIATIVIDAD
    -> izquierda a derecha
    <- derecha a izquierda
    i=i+2
    i+=2

    . CONTROL DE
    FLUJO

    Proposiciones
    Se terminan con ;
    (";" es terminador, no separador)
    Nula: ;
    Simple: x=0;
    Compuesta: { proposiciones; }
    if else
    if (expresión)
    proposición 1
    else
    proposición 2
    Las siguientes proposiciones son equivalentes:
    if (expresión)
    if (expresión != 0)

    El "else" se asocia a la condicional más interna:
    if (n>0) if(a>b) z=a; else z=b;
    Se entendería como:
    if (n>0)
    if(a>b)
    z=a;
    else
    z=b;
    Si se quiere que el "else" se asocie a la condicional externa, es
    necesario usar llaves, como se muestra a
    continuación:
    if (n>0) { if(a>b) z=a;} else z=b;
    que se entiende como:
    if (n>0) {
    if(a>b)
    z=a;
    }
    else
    z=b;

    else if
    Permite escribir condicionales de casos
    EXCLUYENTES
    if (expresión)
    proposición
    else if (expresión)
    proposición
    else
    proposición

    switch
    Sintetiza una secuencia larga else if,
    incluyendo || (or).

    Ej.

    main() /* cuenta dígitos, espacios en blanco y
    otros */
    {

    int c, i, nwhite, nother, ndigit[10];
    nwhite=nother=0;
    for (i=0; i<10; i++)
    ndigit[i]=0;
    while ((c=getchar()) != EOF) {

    switch(c) {

    case '0':
    case '1':

    case '9':

    ndigit[c-10]++;
    break;

    case ' ':
    case 'n':
    case 't':

    nwhite++;
    break;

    default:

    nother++;
    break;

    }

    }

    printf("digits= ");
    for (i=0; i<10; i++)
    printf("%d",ndigit[i]);
    printf("n white space = %d, ",
    "other = %dn",nwhite,nother);
    return 0;
    }

    while y for
    while (expresión)
    proposición
    Las siguientes proposiciones "for" y "while" son
    equivalentes:
    for (expr1; expr2; expr3)
    proposición
    expr1;
    while (expr2)
    {

    proposición
    expr3;

    }
    Uso de la coma ","
    La coma
    "," permite el cálculo
    secuencial de expresiones.

    Por ejemplo:

    reverse(s) /* invierte cadena s */
    char s[];
    {

    int c, i, j;
    for (i=0; j=strlen(s)-1; i) 

    {

    c=s[i];
    s[i]=s[j];
    s[j]=c;

    }

    }

    do while
    do
    proposición
    while (expresión);
    break
    La proposición "break" permite una salida
    forzada de:

    • do
    • while
    • for
    • switch

    Puede similarse usando otra "condición", pero no
    resulta tan claro.
    continue
    Obliga a ejecutar la siguiente
    iteración del ciclo, en las proposiciones:

    • do
    • while
    • for

    Por ejemplo

    /* procesa los valores
    positivos de un arreglo */
    for (i=0; i
    {
    if (a[i]<0) /* salta los elementos negativos */
    continue;
    /* aquí procesa los elementos positivos */
    }

    goto y etiquetas
    Generalmente es usada en el
    manejo de errores. Se aconseja ser parcos en su uso.
    Por ejemplo

    /* muestra el primer valor negativo
    de un */
    /* arreglo multidimensional */
    for (i=0; i
    for (j=0; j
    if (v[i][j]<0)
    goto found;
    /* no se encontró */
    found: /* se encontró en la posición i,j */
    ..

    FUNCIONES Y LA
    ESTRUCTURA DEL
    PROGRAMA

    En C no se pueden escribir funciones dentro de
    funciones.
    Por ejemplo:

    /* Imprime las líneas que contengan cierto
    patrón */
    #define MAXLINE 100
    void index(char [], char []);
    extern void getline(char [], int);
    main()
    {
    char line[MAXLINE];

    while(getline(line,MAXLINE)>0)
    if (index(line,"the")>=0
    printf("%s",line);

    }
    void index(char s[], char t[])
    /* devuelve posición t en s; o -1 si no está */
    {
    int i,j,k;

    for (i=0; s[i]!=''; i++)
    {

    for (j=i, k=0; t[k]!='' && s[j]==t[k];
    j++,k++);
    if (t[k]=='') return (i);

    Compilación y encadenamiento
    En
    UNIX:
    $ cc main.c getline.c index.c
    produce:
    main.o getline.o index.o <- programas
    objeto
    a.out <- programa ejecutable
    Funciones que devuelven valores no
    enteros
    Se tienen las siguientes 2 puntos:
    – Por default el tipo de la función es "int" ("char" se
    convierte a "int").
    – En caso de no ser "int", la función se debe
    declarar:
    – en la función:
    double atof(s) /* convierte la cadena s a double */
    – en la llamada:
    double sum,atof();

    (… sum+=atof(line));
    Reglas sobre el alcance de validez de una
    variable:
    Variable externa (declaración)
    Se dan a conocer las propiedades de una variable, por ejemplo
    tipo, tamaño, etc.
    Variable externa (definición)
    Causa una asignación de memoria. Solo se
    debe hacer una definición.
    Por ejemplo, las siguientes líneas

    int sp;
    double val[MAXVAL];

    cuando están fuera de cualquier función,
    definen las variables externas "sp" y "val", obligan a asignar
    memoria y sirven de declaración para el resto del archivo.
    Sin embargo, las líneas

    extern int sp;
    double val[MAXVAL];

    declaran para el resto del archivo que "sp" es un
    entero, y "val" es un arreglo double (cuyo tamaño se fija
    en otro lugar), pero no se crean las variables ni se les asigna
    memoria.
    Variables estáticas
    Las variables
    estáticas son accesibles solo dentro del archivo donde son
    definidas. Y pueden ser definidas dentro o fuera de una
    función.
    Ej. Si las 2 variables y las 2 funciones siguientes se
    compilan
    en un archivo con:

    static char buf[BUFSIZE]; /* buffer para "ungetch"
    */
    static int bufp=0; /* sig. pos. libre en "buf" */
    getch() {…}
    ungetch() {…}
    el resto de las funciones de los otros archivos no
    tendrá acceso ni a "buf" ni a "bufp". Por lo anterior, no
    habrá conflictos si
    los mismos nombres son usados en otros programas.
    Una función estática
    es inaccesible fuera del archivo donde se declara (y define, por
    supuesto).
    Variables registro.
    Las variables registro
    sólo pueden ser las variables automáticas y los
    parámetros formales de la función.
    Las variables registro son usadas para variables muy usadas. El
    compilar coloca las variables registro en los registros de la
    CPU de la
    máquina, siempre y cuando sea posible.
    NO ES POSIBLE obtener la dirección de una variable
    estática.
    Se declaran de la siguiente manera:
    register int x;
    register char c;
    Y la declaración para parámetros formales de
    función, es:
    f(register int c,n)
    {

    }
    Estructura de bloques
    Se tienen las siguientes
    características:
    – No se pueden definir funciones dentro de funciones. Si embargo
    si se pueden declarar funciones dentro de funciones. Esta
    declaración hace referencia a funciones que se encuentran
    en otro parte.
    – Las declaraciones o definiciones (incluyendo inicializaciones),
    se colocan dentro de las llaves que introduce cualquier sentencia
    compuesta.
    Por ejemplo:
    if (n>0)
    {
    /* se declara una variable nueva "i" */
    int i;
    for (i=0; i

    Inicialización
    La inicialización tiene
    las siguientes consideraciones:
    – Si no se inicializan explicitamente las variables, se
    tiene:
    – Las variables externas y estáticas tendrán
    cero.
    – Las variables automáticas y registro tendrán
    basura.
    – Las variables simples, que no son arreglos ni estructuras,
    se inicializan así:
    int x;
    char squoute = ''';
    long day=60*24; /* minutos del día */
    – Las variables externas estáticas se inicializan una vez
    en tiempo de compilación; las variables automáticas
    y registro, cada vez que se entra a la función.
    – Las variables automáticas y registro se pueden
    inicializar con valores definidos previamente, incluso llamadas a
    función. Por ejemplo:
    int low=0;
    int high=n-1; /* n definida anteriormente */
    int mid;
    ..
    }
    – Los arreglos automáticos no pueden ser incializados.
    – Los arreglos externos y estáticos se inicializan con
    valores separados por ',' y entre llaves. Por ejemplo, el
    programa siguiente para contar dígitos, espacios y
    otros:
    /* cuenta dígitos, espacios y otros */
    main()
    {
    int c,i,nwhite,nother;
    int ndigit[10];
    nwhite=nother=0;
    for (i=0; i<10; i++)
    ndigit[i]=0;

    }
    puede ser escrito como:
    /* cuenta dígitos, espacios y otros */
    int nwhite=0;
    int nother=0;
    /* inicialización con 10 0's */
    int digit[10]={0,0,0,0,0,0,0,0,0,0,0};
    main()
    {
    int c,i;

    }
    – Se pueden inicializar arreglos de caracteres de 2 maneras:
    – Como cadena de caracteres
    char pattern[]="the";
    – Como arreglo de caracteres
    char pattern[]={'t','h','e',''};
    Recursividad
    – Las funciones en C pueden llamarse a si
    mismas, es decir pueden ser recursivas.
    – Una función puede llamarse a si misma, directa o
    indirectamente. Por ejemplo:

    /* imprime n en decimal (recursivamente) */
    void printd(int n)
    {
    int i;
    if (n<0)
    {
    putchar('-');
    n=-n;
    }
    if ((i=n/10) != 0)
    printd(i);
    putchar(n%10+'0');
    }

    El preprocesador de C
    Inclusión de archivos (include):
    Una línea
    de la forma
    #include "nombre"
    indica al preprocesador de C, substituir la línea con el
    contenido del archivo "nombre", de trayectoria absoluta.
    Una línea de la forma
    #include <nombre>
    indica al preprocesador de C, substituir la línea con el
    contenido del archivo "nombre", de la trayectoria PREDEFENIDA
    para los archivos "include".
    Los "include"s pueden ser anidados.
    Los "include"s son recomendables para tener las mismas
    definiciones en varios programas fuentes.
    Sustitución de Macros
    Para sustituir SI por 1,
    usamos la línea siguiente.
    #define SI 1
    aquí, las cadenas "SI=" no serán sustituidas.
    Para usar una sintaxis similar al PASCAL, usamos
    las líneas
    #define then
    #define begin {
    #define end }
    y podríamos escribir después
    if (i>0) then
    begin
    a=1;
    b=2
    end
    Podemos usar parámetros en la sustitución de
    macros. Por
    ejemplo:
    #define max(A,B) ( (A)>(B) ? (A) : (B) )
    y usarla como
    x=max(p+q,r+s);
    que sería sustituida por
    x=((p+q)>(r+s) ? (p+q) : (r+s));
    NOTAS:
    – Es necesaria utilizar paréntesis en la definición
    de macros, para evitar resultados erróneos debido a la
    prioridad de las operaciones
    aritmÚticas.
    – Con una MACRO se puede crear una sola función para
    varios tipos de argumentos.
    – Las MACROS con parámetros son más eficientes que
    las llamadas a funciones, ya que son una expansión en
    línea. Por ejemplo, las funciones "getchar()" y
    "putchar()" están definidas como MACROS de las funciones
    "putc()" y "getc()", usando la salida estándard (stdout) y
    entrada estándard (stdin) respectivamente.

    Apuntadores y
    arreglos.

    Apuntadores y direcciones.

    Los símbolos * y & pueden ser usados para
    el contenido y la dirección de una variable,
    respectivamente. Por ejemplo,
    si "x" es una variable de tipo "int"
    y "y" es una variable de tipo "int"
    y "px" es una variable de tipo "apuntador a int"
    entonces, se podría hacer lo siguiente:
    Asignar la dirección de "x" al apuntador "px"
    px = &x;
    Aumentar en 1, el valor apuntado por "px" (es decir, el valor de
    "x") y asignarlo a la variable "y".
    y = *px+1;
    Aumentar en 1, el valor del apuntador "px" (es decir, el valor de
    una variable desconocida) y asignarlo a la variable "y".
    Aumentar en 1 el valor apuntado por "px" (es decir, el valor de
    "x").
    *px+=1;
    o bien
    (*px)++;
    notar que en este último ejemplo es necesario usar
    parÚntesis, debido a que, aunque la prioridad de "*" y
    "++" es igual, la asociatividad es de DERECHA a IZQUIERDA.
    Así, sin los parÚntesis, la expresión
    "*px++;" se entendería como: "*(px++);".

    APUNTADORES Y ARREGLOS
    Se definimos el arreglo
    de 10 enteros de la siguiente manera:
    int a[10];
    podemos referenciar a[0] a[1] .. a[9].
    Si además definimos el apuntador a entero "pa"
    int *pa;
    y le asignamos la dirección del primer elemento del
    arreglo "a",
    pa=&pa[0]; o bien pa=a;
    entonces, el contenido de "a[i]" puede ser visto con
    *(pa+i)
    En apuntadores a arreglos de caracteres, las 2 siguientes
    declaraciones son equivalentes:
    char s[];
    char *s;
    AritmÚtica de direcciones.
    Son posibles las siguientes operaciones con apuntadores:
    – Sumar y restar un entero a un apuntador.
    – Restar y comparar 2 apuntadores.
    – Comparar un apuntador con NULL.
    Apuntadores a caracteres y a funciones.
    En el siguiente ejemplo, la variable "mensaje" es SOLO UN
    APUNTADOR.
    char *message="now is the time";
    No se debe comfundir el envío de un APUNTADOR a un arreglo
    de caracteres con el envío del ARREGLO de caracteres. Por
    ejemplo, en la siguiente función se envían los
    apuntadores a 2 arreglos de caracteres (cuya memoria fue asignada
    en otra parte del programa).
    strcpy(s,t) /* copia t a s, con apuntadores */
    {
    while (*s++=*t++)
    ;
    }
    Arreglos Multidimensionales
    En C, los arreglos de 2
    dimensiones se implementan como arreglos unidimensionales. Donde
    cada elemento es, a su vez, un arreglo unidimensional. Por lo
    anterior, la sintaxis en C es
    day_tab[i][j]; /* [renglón] [columna] */
    en lugar de:
    day_tab[i,j]; /* INCORRECTO */
    Los arreglos de 2 dimensiones pueden ser inicializados como
    sigue:
    static int day_tab[2][13] =
    {
    {0,31,28,..,31},
    {0,31,29,..,31},
    };
    Arreglo de apuntadores. Apuntadores a apuntadores.
    Inicialización de arreglos de apuntadores:
    static char *name[]=
    {
    "mes ilegal",
    "enero",

    "diciembre",
    };
    Diferencia entre apuntadores y arreglos
    multidimensionales.
    No se debe confundir las
    declaraciones:
    int a[10][20]; /* matriz de
    10*20=200 enteros */
    int *b[10]; /* vector de 10 apuntadores a enteros */
    /* o 10 apuntadores a arreglos a enteros */
    Si consideramos que en los 2 arreglos anteriores, usamos
    [renglón] [columna]
    Entonces tenemos 2 diferencias básicas:
    1. En el arreglo "a" el número de columnas (elementos) x
    renglón es 20 para todos los renglones. En el arreglo "b"
    podemos tener un número diferente de columnas x
    renglón para cada renglón. Por ejemplo 2 elementos
    en el renglón 0; 5 en el renglón 1; e incluso una
    matriz de 4×4 en el renglón 3, etc.
    2. La memoria
    ocupada por los 2 arreglos es diferente. Inclusive en el caso de
    que los apuntadores del arreglo "b" apuntaran a un arreglo de 20
    elementos por renglón, la memoria ocupada por los 2
    arreglos sería diferente.
    Para el arreglo "a", 200 enteros.
    Para el arreglo "b", 200 enteros + 10 apuntadores.
    Argumentos de la línea de comandos.
    Al correr el programa ejecutable
    producido por un programa fuente escrito en C, podemos agregar
    argumentos en la línea de comandos. Estos argumentos
    pueden ser usados para producir efectos diferentes al correr el
    mismo programa. Así, podríamos usar opciones como
    las usadas en los sistemas
    operativos:
    C:> copy
    C:> copy a:arch1 b:
    C:> copy a:arch1 b:arch2
    El procesamiento de los argumentos de la línea de comandos
    se puede ejemplificar con el siguiente programa en C, que
    simplemente escribe los argumentos en la salida
    estándard.

    /* escribe los argumentos en la salida estándard
    */
    main(int argc, char *argv[])
    {
    while(–argc>0)
    printf("%s%c",*++argv,(argc>1)?' ':'n');
    }

    "argc" y "argv" son palabras predefinidas. "argc" indica
    el número de argumentos (incluyendo el nombre del programa
    ejecutable). "argv" es un arreglo de apuntadores a arreglos de
    caracteres. "argv[i]" es un apuntador al arreglo de caracteres
    del argumento i.
    Por ejemplo, si "echo.exe" es un programa ejecutable producido
    por un programa escrito en C, entonces al ser corrido con:
    echo hello world
    los valores que tomarían "argc" y "argv" en caso de haber
    sido usados son:
    argc=3 *argv[0]=echo *argv[1]=hello *argv[2]=world
    Apuntadores a funciones
    En la definición:
    /* compara 2 cadenas */
    int strcmp();
    En la declaración:
    /* apuntador a función que devuelve un entero */
    int (* comp)();

    /* función que devuelve apuntador a entero */
    int *comp();

    . ESTRUCTURAS

    Por ejemplo, si queremos crear el tipo "date" y crear 2
    variables de ese tipo, "birthdate" y "hiredate". Podemos
    usar:
    struct date
    {
    int day;
    int month;
    int year;
    };
    date birthdate, hiredate;
    o bien, también podemos escribir:
    struct date
    {
    int day;
    int month;
    int year;
    } birthdate, hiredate;
    Si solo queremos crear las variables, y no llamar a su tipo con
    algún nombre, podemos simplemente teclear:
    struct
    {
    int day;
    int month;
    int year;
    } birthdate, hiredate;
    Una estructura puede contener a su vez estructuras, como en:
    struct person
    {
    char name[NAMESIZE];
    char address[ADRSIZE];
    long zipcode;
    double salary;
    struct date birthdate;
    struct date hiredate;
    }emp;
    En el caso de haber declarado la variable "emp" de la forma
    anterior, podemos hacer referencia al mes de su fecha de
    nacimiento con:
    emp.birthdate.month
    También podemos inicializar estructuras estáticas y
    externas de la siguiente manera:
    struct date d={4,7,1776}
    Si declaramos apuntadores a estructuras, como en
    struct date *pd;
    podemos hacer referencias con la notación:
    pd->year
    o bien
    (*pd).year
    NOTAS:
    – punto(.) -> () [] tienen la máxima precedencia
    Por lo tanto,
    ++p->x incrementa x
    – La asociatividad de punto(.) y -> es de izq. a der.
    Por lo tanto,
    p->q->memb
    se entiende como (p->q)->memb
    emp.birthdate.month
    se entiende como (emp.birthdate).month

    Arreglos de estructuras
    En lugar de usar
    arreglos paralelos en C, como en el ejemplo siguiente para contar
    palabras reservadas de C,
    char *keyword[NKEYS];
    int keycount[NKEYS];
    se pueden usar estructuras, de la siguiente manera:
    struct key
    {
    char *keyword;
    int keycount;
    } keytab[NKEYS];
    pero tendremos que asignar valores despuÚs a "keytab".
    También podemos usar declaración explicita como
    en:
    struct key
    {
    char *keyword;
    int keycount;
    } keytab[]=
    {
    "break",0,
    "case",0,

    "while",0
    };
    #define NKEYS (sizeof(keytab)/sizeof(struct key))
    donde se define NKEYS en base a los tamaños de la
    estructura y la declaración explícita, para no
    tener que calcular su valor y recalcularlo cada vez que el
    contenido de "keytab" cambie.

    Apuntadores a estructuras
    Se pueden declarar
    apuntadores a estructuras, como por ejemplo, si usamos la
    estructura "key" anteriormente definida:
    struct key *binary(),*pk;
    y podemos referenciar a los campos de la estructura con:
    pk->keyword
    pk->keycount
    Estructuras autoreferenciadas
    Las estructuras pueden
    contener apuntadores a si mismas como se muestra en el siguiente
    ejemplo:
    struct tnode /* el nodo */
    {
    char *word; /*
    apuntador a los caracteres */
    int count; /* número de ocurrencias */
    struct tnode *left; /* hijo izquierdo */
    struct tnode *right; /* hijo derecho */
    };
    Se puede convertir un apuntador a caracter en un apuntador de
    estructura mediante el uso de un 'cast' (conversión
    forzada).
    char *p;
    … (struct tnode *) p …
    La anterior conversión es usada principalmente en el uso
    de memoria dinámica.

    Uniones
    Las uniones son usadas cuando se necesita que
    una variable tome valores de tipos diferentes. En el ejemplo
    siguiente:
    union u_tag
    {
    int ival;
    float fval;
    char *pval;
    } uval;
    la variable "uval" de tipo "u_tag" puede tomar valores
    "int" si se usa "uval.ival"
    "float" si se usa "uval.fval"
    "char *" si se usa "uval.pval"
    Es necesario el uso consistente de uniones. Es decir, el tipo
    utilizado debe ser el tipo más recientemente
    almacenado.
    Las uniones pueden ser anidadas en una estructura, como se
    muestra:
    struct
    {
    char *name;
    int flags;
    int utype;
    union
    {
    int ival;
    float fval;
    char *pval;
    } uval;
    } symtab[NSYM];
    y se hace referencia de la siguiente manera:
    symtab[i].uval.ival para ival
    symtab[i].uval.pval para el primer caracter de pval
    typedef
    El "typedef" permite declarar sinónimos
    de tipos. Por ejemplo
    typedef int LENGTH;
    declara el nombre de LENGTH como sinónimo de int.

    Este "nuevo tipo" podría ser usado en
    LENGTH len, maxlen;
    LENGTH *lengths[]; /* arreglo de apuntadores a tipo LENGTH=int
    */
    Algunas observaciones del uso de "typedef"
    – Sintácticamente "typedef" se parece a las clases de
    almacenamiento
    "extern", "static", etc.
    – No crea un nuevo tipo, sino añade un nuevo nombre.
    – Es parecido a "#define" pero con mayor alcance. Por ejemplo, el
    siguiente sinónimo es para un apuntador a una
    función que devuelve un int.
    typedef int (*PFI) ();
    ..
    PFI strcmp, numcmp, swap;

    . ENTRADA Y SALIDA

    Acceso a la biblioteca
    estándard
    La línea siguiente se
    coloca al principio de un programa fuente. Define ciertas macros
    y variables empleadas por la biblioteca estándard de
    E/S.
    #include
    Se usa < >, en vez de "", para que el archivo sea buscado
    en el directorio de información estándard, por
    ejemplo:
    /usr/include —> en UNIX
    TURBOC2.0INCLUDE —> en MS-DOS

    Entrada y salida estándard: putchar(),
    getchar()
    El uso de la entrada y salida estándard
    permite hacer redireccionamiento de y hacia archivos.
    prog < arch_ent
    prog > arch_sal
    o bien procesamiento entubado, como en:
    prog | otr_prog
    otr_prog | prog
    Por ejemplo, el siguiente programa copia la entrada
    estándard (teclado) a la
    salida estándard (monitor).

    #include <stdio.h>
    main()
    {
    int c;

    while ((c=getchar())!=EOF)
    putchar(isupper(c) ? tolower(c) : c);

    }
    y podría correrse, en el casO
    de llamarse "lower", de la siguiente manera:
    C:> type file1 | lower > salida

    Salida con formato, printf()
    La sintaxis es la
    siguiente:
    printf(control,arg1,arg2,…,argn)
    donde:
    control::="{char}%[-][long_max]convers.[char_o_decim]{char}"
    char ::=cualquier caracter
    – justificación a la izquierda
    long_max::=longitud máxima. Si no cabe el valor, se
    viola
    convers::=d decimal
    o octal
    x hexadecimal
    u unsigned
    c caracter
    s cadena(string)
    e float o double => [-]m.nnnnnnE[+-]xx
    f float o double => [-]mmm.nnnnnn
    g más corto que %e o %f. Los ceros no significativos no se
    imprimen
    char_o_dec número de caracteres de la cadena o
    número de decimales
    Por ejemplo, si "s" es un apuntador a "hello, world", se
    tiene:
    0 1 2
    1234567890123456789012
    printf(":%10s:",s) => :hello world:
    printf(":%-10s:",s) => :hello world:
    printf(":%20s:",s) => : hello world:
    printf(":%-20s:",s) => :hello world :
    Entrada con formato, scanf()
    La sintaxis es la siguiente:
    scanf(control,arg1,arg2,…,argn)
    donde:
    control::="{char}%[*]convers[long_max]convers"
    char::=cualquier caracter
    convers::= d decimal
    o octal
    x hexadecimal
    h entero corto (short)
    c caracter
    s cadena
    f,e punto flotante. Puede usar E+ o E-
    l long (double)
    Por ejemplo, si declaramos:
    int i;
    float x;
    char name[50];
    entonces, la llamada de la función, líneas
    leídas y valores asignados, se muestran a
    continuació:
    scanf("%d %f %s",&i,&x,name);
    25 54.32E-1 Torres
    => i=25 x=5.432 name="Torres"
    scanf("%2d %f %*d %25",&i,&x,name);
    56789 0123 45182
    => i=56 x=789.0 name="45"

    Conversión de formato en memoria, sprintf(),
    sscanf().
    sprintf() y sscanf() hacen la misma
    función que printf() y sscanf(), pero en lugar de enviar
    el resultado a la salida estándar o leerlo de la entrada
    estándar, usan variables de tipo de arreglo de
    caracteres.
    Por ejemplo, si n=123, la siguiente llamada a sprintf() almacena
    "temp123" en el arreglo de caracteres name.
    sprintf(name,"temp%d",n);
    Y si name contiene "temp123", el valor 123 se asignará a n
    al ejecutarse la siguiente llamada
    sscanf(name,"temp%d",n);

    Acceso a archivos (funciones de stdio.h)
    En la
    librería <stdio.h> está definido el tipo
    FILE. Este tipo permite guardar información de
    posición y descripción del buffer asociado a un
    archivo.
    El tipo FILE se usa de la siguiente forma:
    FILE *fopen(), *fp;
    donde "fp" puede ser usado como apuntador del archivo que se
    abre:
    fp=fopen(nombre,modo);
    donde:
    nombre es el nombre del archivo que se va a abrir
    modo puede ser: lectura("r"),
    escritura("w"), y añadido("a").
    NOTA: si se produce un error, fopen regresa NULL.
    Para escribir y leer información de un archivo, usamos:
    putc() y getc(), de la siguiente manera:
    c=getc(fp); /* lee un caracter del archivo apuntado fp
    */
    putc(c,fp); /* escribe un caracter al arch. apunt. fp
    */
    Existen en la librería <stdio.h> las definiciones
    para 3 apuntadores estándard a archivos:
    stdin archivo de la entrada estándard
    stdout archivo de la salida estándard
    stderr archivo de la salida del error estándard
    En base a los apuntadores estándard anteriores, se pueden
    definir las funciones putchar() y getchar().
    #define getchar() getc(stdin)
    #define putchar(c) putc(c,stdout)
    También podemos usar entrada y salida formateada a
    archivo, con las funciones:
    fscanf(fp,formato,lista de variables);
    fprintf(fp,formato,lista de variables);
    con la misma sintaxis que scanf(),printf().
    NOTA: Cuando se detecta un error de entrada/salida en archivos,
    es conveniente escribir el mensaje de error en stderr.

    Entrada y salida de líneas
    Para almacenar en el
    arreglo de caracteres line, una línea de un máximo
    de MAXLINES caracteres leída del archivo apuntado por fp,
    usamos:
    fgets(line,MAXLINE,fp)
    Para escribir en el archivo apuntado por fp el arreglo de
    caracteres line, usamos
    fputs(line,fp);

    Operaciones con cadenas de caracteres, string.h
    En el
    directorio include de la versión de C que se estÚ
    manejando existen encabezados de otras librerías, entre
    las que se cuentan string.h. En este encabezado están las
    declaraciones para las funciones de manejo de cadenas de
    caracteres que se listan a continuación. En adelante, s y
    t son de tipo apuntador a caracter, y c y n son enteros.
    strcat(s,t); concatena s al final de t
    strncat(s,t,n); concat. n caracts. de t al final de s.
    strcmp(s,t); regresa negativo, cero, o positivo para:
    s<t, s==t, s > t
    strncmp(s,t,n); i gual que strcmp pero solo con n
    caract.
    strcpy(s,t); copia t en s
    strncpy(s,t,n); copia a lo mas n caract. de s en t
    strlen(s); regresa la longitud de s
    strchr(s,c); regresa un apuntador al primer c que
    estÚ en s, o NULL si no está presente.
    strrchr(s,c); regresa un apuntador al último c que
    estÚ en s, o NULL si no está presente.

    Prueba y conversión de cadenas de caracteres,
    ctype.h
    Varias de las funciones declaradas en
    <ctype> realizan pruebas y
    conversiones de caracteres. En lo que se muestra a
    continuación, c es un int que se puede representar como un
    unsigned char o EOF. Las funciones regresan int
    isalpha(c); != 0 si c es alfabÚtica, 0 otro
    caso.
    isupper(c); mayúscula
    islower(c); minúscula
    isdigit(c); dígito
    isalnum(c); isalpha(c) || isdigit(c)
    isspace(c); blanco, tabulador, nueva línea,
    retorno, avance de línea, tabulador vertical
    toupper(c); regresa c convertida a mayúscula
    tolower(c); regresa c convertida a minúscula
    ungetc(c,fp) Esta función se usa para devolver el
    caracter c al archivo apuntado por fp.

    Funcion system()
    La función system() permite
    hacer una llamada al sistema
    operativo. La sintáxis es la siguiente:
    system("date");
    system("dir");

    Memoria Dinámica
    Al declarar (o definir) una
    variable en C, normalmente se establece una memoria limitada. Por
    ejemplo:
    int i;
    int a[10];
    int *c;
    Sin embargo si nosotros queremos que ciertos datos se
    almacenen en memoria no limitada (salvo la limitación del
    "heap" del sistema), podemos
    usar memoria dinámica.
    El siguiente ejemplo muestra como almacenar una cadena
    arbitrariamente larga de caracteres.

    /* programa para almacenar cadena de longitud ilimitada
    */
    #include <stdio.h>
    #include <malloc.c>
    struct scar
    {

    char car; /* caracter */
    struct caract *psig; /* apuntador al siguiente */

    } pini, pfin;

    main()
    {
    int c;
    struct caract pc;

    /* lectura y almacenamiento */
    pini=pfin=NULL
    if (c=getchar()!=EOF) do c=getchar();
    for (pini=pfin=NULL; (c=getchar())!=EOF; )
    pfin=(struct scar *) malloc(sizeof(struct scar))
    if (pfin=NULL)
    puts("No hay memoria",stderr);
    else
    pini->car=c, pini->psig=NULL)
    while (c!=EOF);

    Oscar Quintero

    Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

    Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

    Categorias
    Newsletter