Punteros (repaso)

Punteros y arreglos

  • El nombre de una variable de tipo arreglo es un puntero a la primera posición del arreglo
    
    double a[20];
             /* a == &a[0]  */
    

  • Podemos acceder al valor almacenado en un elemento de un arreglo de dos formas:
    • Usando el subíndice: a[3]
    • Usando aritmética de punteros para
      la dirección de memoria *(a+3)

Relación entre índices y punteros




a[0] ==   *a   == 3
a[1] == *(a+1) == 4
a[2] == *(a+2) == 7
a[3] == *(a+3) == 2
...
a[9] == *(a+9) == 6

Ejemplo: ¿Qué hacen estas sentencias?



int i, *pA;

int arreglo[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};

pA = arreglo;

printf("%d,%d\n", *pA, arreglo[0]);
            /* Al contenido de *pA (arreglo[0]) le suma i */

for(i=0; i < 10; i++)
      printf("%d, %d\n", arreglo[i], *pA+i);

for(i=0; i < 10; i++)
      printf("%d, %d\n", arreglo[i], *(pA+i));
                                      /* Equivalente a arreglo[i] */

Puntero NULL

  • p = NULL;
    • Puntero que no apunta a ninguna dirección
    • Valor común para todos los tipos puntero definido en <stdlib.h>
  • Asignación:
    
    pc = pv = NULL;
    
  • No se puede desreferenciar, por que *pc no existe


Nota: En realidad la dirección de memoria 0x0 existe,
pero siempre esta reservada para fines específicos
de la arquitectura. Por esto el lenguaje C lo considera
como un puntero especial a nada.

Resumiendo...

  • Punteros
    • Variables que guardan direcciones de memoria de variables de un tipo base
    • Apunta a una variable de tipo base
  • Permiten el paso por referencia en funciones
    • Permite devolver valores a través de parámetros
  • Aritmética de punteros:
    • Como moverse entre variables del mismo tipo...

Conversiones de tipos (casting)

  • Para los ejemplos:
  • 
    float a;
    int b;
    

  • Conversiones automáticas
    • De entero a flotante:
      
      a = 4 + 4.0 -> 4.0 + 4.0 -> 8.0
      
    • De flotante a entero:
      
      b = 3.5 + 3 -> 3.5 + 3.0 -> 6.5 -> 6
      
  • Conversiones manuales o explicitas (casting de tipos)
    
    (float) 1 -> 1.0
    (int) 1.5 -> 1
    

Ruptura de reglas de tipado

    int tabla[3];
    int *pi;
    char *pc;
    
    pi = tabla;
    *pi = 97;
    *(pi+1) = 98;
    
    pc = (char *) pi;
    
    *pc = 'x';
    *(pc+1) = 'y';
    

Aritmética de punteros

  • A los punteros se les puede sumar y restar enteros
    • El incremento subyacente es multiplicado por el tamaño del tipo base
    • Se entiende que el puntero puede apuntar a un array indefinido de elementos del tipo base, no se comprueban limites
  • Se pueden restar entre sí
    • Deben ser del mismo tipo y apuntar al mismo array, en ese caso nos da la distancia entre elementos del array
  • No se pueden sumar entre sí (ni otras operaciones), no esta definido (resultados impredecibles)

El operador sizeof

sizeof

  • sizeof es un operador de C (como ! o ~) que retorna un "constant int" que nos dice el tamaño de cualquier dato.
  • El elemento a examinar puede ser un dato, un porción de un dato o un tipo de dato.
  • sizeof retorna el tamaño del elemento en chars (bytes/size_t)
  • sizeof también puede averiguar el tamaño de un array:
    
    #include <stdio.h>
    
    void main(void) {
    char cadena[] = "Mi string de prueba";
    int vector[] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};
    printf("Mi \"cadena\" tiene %d caracteres\n",
                     (int)(sizeof(cadena)/sizeof(char)));
    printf("Mi \"vector\" tiene %d posiciones\n",
                     (int)(sizeof(vector)/sizeof(int)));
    }
    

sizeof

Como el sizeof lo hace el compilador el lo sabe por que también maneja la declaración. Pero la variable debe haber sido declarada explicitamente como un vector:


char string[32] = "hello, world";
char *ptr = string;


  • sizeof (string)
    • Devuelve: 32
  • sizeof (ptr)
    • Si estamos en una máquina con punteros de 4 bytes...
    • Devuelve: 4


http://www.gnu.org/software/libc/manual/html_node/String-Length.html

Arreglos multidimensionales (matrices)

  • Declaración:
    
    {tipo-base}  {identificador}[{NumElem1}][{NumElem2}];
    
  • Declaración y asignación:
    
    tipo-base identif[M][N] = {
             {valor0_0, valor0_1, ..., valor0_N-1},
             {valor1_0, valor1_1, ..., valor1_N-1},
             {valor2_0, valor2_1, ..., valor2_N-1},
             ...,
             {valorM-1_0, valorM-1_1, ..., valorM-1_N-1}
    };
    
  • Asignación:
    
    matriz[indice1][indice2] = valor;
    

Ejemplos de declaración y uso de Matrices (I)



  • Declaración de una matriz de 50 filas de 20 enteros:
    
    int matriz[50][20]; 
           /* 50 filas x 20 columnas */
    

  • Declaración e inicialización de una matriz de 2x3:
    
    int matriz[2][3] = {
                { 2, 5, 8 },
                { 9, 1, 2 }
                };
    

Ejemplos de declaración y uso de Matrices (II)



  • Asignando un valor a la primera posición de la segunda fila de una matriz de enteros:
    
        matriz[1][0] = 50;
    

  • Imprimiendo una matriz de 100 x 50 enteros mediante ciclos for:
    
    int i, j;
    for (i=0; i < 100; i++)
        for (j=0; j < 50; j++)
            printf("%d\n", matriz[i][j]);

¿Y si usamos 3 dimensiones?


    • Declaración:
      
      int v[2][2][2]={
      	{{1,2},{3,4}},
      	{{5,6},{7,8}}
      	};
      

    • Recorriendo la matriz:
      
      for(i=0;i<2;i++)
          for(j=0;j<2;j++)
              for(k=0;k<2;k++)
                  printf("%d",v[i][j][k]);
      
    • Ejemplo: matrices.c


Funciones de manejo de strings

Librerias


  • STDIO.H
    • char *fgets(char *s, int size, stdin);
    • int fputs(const char *s, stdout);

  • STRING.H
    • strcat(), strcpy(), strlen()
    • strchr(), strcmp(), strcmpi(), strncmp()
    • strtok()


Nota: El stdin es el teclado, y el stdout es la pantalla.

size_t strlen(const char *s);



#include <stdio.h>
#include <string.h>

int main(void) {
    char *string = "Curso Informatica 1";
    printf("%d\n", strlen(string));
    return 0;
}

size_t: Es un tipo que permite representar el tamaño de cualquier objeto en bytes.
Es el tipo de dato que retorna el operador sizeof y es muy usado
por la librería estándar para representar tamaños y cuentas.

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



#include <stdio.h>
#include <string.h>

int main(void) {
   char string[10];
   char *str1 = "abcdefghi";

   strcpy(string, str1);
   printf("%s\n", string);
   return 0;
}

Nota: Esta función siempre asume que en destino hay suficiente lugar para copiar todos los elementos de origen. Si este no fuera el caso el programa fallará!

char *strcat(char *dest, const char *src);



#include <string.h>
#include <stdio.h>

int main(void) {
   char destination[25];
   char *espacio = " ", *s1 = "Curso", *s2 = "Informatica 1";

   strcpy(destination, s1);
   strcat(destination, espacio);
   strcat(destination, s2);

   printf("%s\n", destination);
   return 0;
}

Nota: Esta función siempre asume que en string1 hay suficiente lugar para copiar todos los elementos de string2. Si este no fuera el caso el programa fallará!

¿Como evitamos problemas por no tener espacio suficiente en el string de destino?

Para srtcpy() y strcat()


Podemos usar : strncpy() y strncat()



char *strncpy(char *dest, const char *src, size_t n);
char *strncat(char *dest, const char *src, size_t n);

int strcmp(const char *s1, const char *s2);

int strcmpi(const char *s1, const char *s2);


#include <string.h>
#include <stdio.h>

void main(void) {
   char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";
   int ptr;
   ptr = strcmp(buf2, buf1);
   if (ptr > 0)
      printf("buffer 2 es mayor que buffer 1\n");
   else
      printf("buffer 2 es menor que buffer 1\n");
   ptr = strcmp(buf2, buf3);
   if (ptr > 0)
      printf("buffer 2 es mayor que buffer 3\n");
   else
      printf("buffer 2 es menor que buffer 3\n");
}

Librerías y Funciones


  • STDIO.H
    • Int getchar(void) & int putchar(int c)

  • CTYPE.H
    • isalnum(). isalpha(), isascii(), iscntrl(), isdigit()
    • islower(), isupper(), isprint(), ispunct(), isspace()
    • tolower(), toupper(), isxdigit(), more...

  • STDLIB.H

http://www.gnu.org/software/libc/manual/

Código

CURSES.H : Compilación


Instalando y copilando:



$ sudo apt-get install libncurses5-dev
$ gcc -o ncurses ncurses1_helloworld.c -lncurses 

Clase practica

Ejercicios

Realizar el estructograma y la codificación en C

  1. Extraer un substring
    
    int substring(char st_salida[], char st_entrada[], int pos, int n)
    
    • Ejemplo:
      • substring(str,"Curso de informatica1", 10, 4);
      • Imprime "info"

  2. Función que hace preguntas
    
    char *pregunta(char texto[], char opc1[], char opc2[])
    

  • Ejemplo:
    • pregunta("Quiere estudiar hoy? ", "si", "no");
    • Imprime: "Quiere estudiar hoy? (si/no)"
    • y retorna "si" o "no"

Ejercicios:

  • Extraer un substring: De la clase anterior...
  • Organizar vector: Leer un conjunto de 100 valores a razon de uno por vez. Formar el vector PAR con los valores pares del conjunto y el vector POS con los valores positivos. Imprimir ambos vectores. Si alguno de ellos o ambos no contienen ningun elemento, informar con una leyenda.

Ejercicio 4.27

  • IP: 4 numeros de 0 a 255 separados por puntos.
    • Primer llamado: strtok(str,'.');
    • Siguientes llamados: strtok(NULL,'.');
  • Email: 2 string de caracteres separado por '@'
    • Los strings pueden tener numeros y caracteres, usar isalphanum()
    • Ambos string pueden tener '.' , '_' o '-'
  • CC: Ver algoritmo de Luhn

Apendice

Problemas con scanf()

Scanf() y el buffer stdin:

  • scanf("%c"); scanf("%s");
  • ¿Como evitamos el buffer?
    • fflush(stdin); /* no suele andar */
    • setbuf(stdin,NULL); /* Anda mejor */
    • scanf(" %c"); /* mejor para Linux */
    • scanf("%3.2f"); scanf("%.2f);
  • O usamos funciones especificas para string y chars de stdio.h:
    • int getchar(void);
    • char *gets(char *s);
    • int putchar(int c);
    • int puts(const char *s);
  • Ver código de fflush()/setbuf()

Mas sobre ncurses (y kbhit):



Mas ejemplos y informacion sobre como usar ncurses.

CONIO.H (BC-DOS)

En BolarndC existia estas funciones


/* Con y sin eco */
int getch(void) & int getche(void)

/* Solo implementado en CONIO.H */
int putch(int ch)

---

Usando NCURSES


sudo apt-get install libncurses-dev
gcc -lcurses -o ej1 mi_ejercicio.c

Notas sobre conio.h y NCURSES