Autor Tema: Guía definitiva de Manejo Punteros en C/C++  (Leído 4255 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado CompSystems

  • PIC18
  • ****
  • Mensajes: 488
    • Home Page
Guía definitiva de Manejo Punteros en C/C++
« en: 07 de Noviembre de 2012, 14:26:18 »
Como les he comentado programo calculadoras Hewlett Packard y un lenguaje de esta es interpretado (UserRPL) , por esta razón no se crea un archivo ejecutable, sino que lee el programa secuencialmente, uno de los problemas de los lenguajes interpretados es que hacen muchas copias de los datos gastando tiempo valioso en el proceso, mientras que los lenguajes compilados y en especial los que manejan punteros aprovechan al máximo la memoria, una manera de aprovechar la memoria es trabajar con punteros, que le "dicen" a la maquina donde esta el dato sin hacer una copia de el cuando se transmite información dentro del algoritmo.

Para muchas personas cuando ven códigos con punteros se asustan, he creado un pequeño programa donde ilustro como se comportan los nombres identificadores punteros (lógica de punteros), espero este sea de utilidad y ademas me comenten si es realmente una guía o lo contrario quedaron peor de lo que conocían, también si quieren aportar algo, bienvenido sea, que gusto ver una animación o simulación de almacenamiento de lógica de punteros, pienso que es realmente como se entendería rápidamente

Gracias


Código: C++
  1. // Ejemplo version 0.07, 06 Dic 2012 By: CompSystems  
  2.  
  3. // Se la paso la vida anhelando que pasara algo maravilloso y lo unico que paso fue la vida.
  4.  
  5. #include<iostream>
  6. using namespace std;
  7. #include <cstdlib>
  8.  
  9. typedef unsigned char Byte;
  10.  
  11. #define NO 0 // No NewLine // No Imprimir una linea en blanco
  12. #define NL 1 // NewLine // Imprimir una linea en blanco
  13. #define PS 2 // Pausar
  14.  
  15. #define Flag_Pausar 0 // Cambiar 1 para activar las Pausas, 0 para No Pausar
  16. #define PAUSAR system("PAUSE")
  17. #define noConst // empty
  18.  
  19.  
  20. //Notación utilizada en los comentarios:
  21. //  := (Asignación) por ejemplo a := 2, al identificador a, se le asigna el valor de 2
  22. //  => (Contenido) por ejemplo a => 2, el identificador a, tiene como contenido el valor de 2
  23. //  idNm (Identifier Name) Nombre Identificador: Variable
  24. //  kIdNm (Constant Identifier Name) Nombre Identificador Constante: Variable solo de lectura.
  25. //  pIdNm (Pointer Identifier Name) Nombre Identificador: Puntero
  26. //  pKIdNm (Constant Pointer Identifier Name) Nombre Identificador: Puntero Constante
  27. //  -> (puntero) por ejemplo p1 -> b, p1 apunta a b. ->p1 => 3, el punt p1 tiene como valor final 3
  28.  
  29. // Funciones para imprimir resultados e informacion
  30. void printStr    ( const char kStr[],                    char TypePrint);
  31. void prtStrAndVal( const char kStr[],       char Value,  char TypePrint);
  32. void prtStrAndChr( const char kStr[],       char Value,  char TypePrint);
  33. void prtStr1And2 ( const char kStr[], const char k2Str[], char TypePrint);
  34. void fnt1_val   (       char *p1_fnt1_val  );
  35. void fnt1_str   ( const char *p1_fnt2_str, char SizeFlag );
  36.  
  37. void function0( const char *p1_fnt0 ){
  38.         prtStrAndVal( "->p1_fnt0=", *(p1_fnt0), NO ); // Imprime cadena
  39. }
  40.  
  41.  
  42. struct strc1_3elements{
  43.         char SubElm1_Byte; // SubElemento1 tipo char
  44.         int  SubElm2_Int; // SubElemento2 tipo Integer
  45.         const char *SubElm3_Array4Elm[ 2 ]; // SubElemento3 tipo char de 2 subelementos (Array)
  46. };
  47.  
  48. void printStrVal3( strc1_3elements X, char TypePrint);
  49.  
  50.  
  51.  
  52. int main( int argc, char *argv[] ){
  53.  
  54.         printStr( "Identificador Estandar:", PS );
  55.         char a = 2; // a := 2 // Declaración y Asignación de un Nombre Identificador (idNm)
  56.         // El idNm (a) tiene como tipo de dato char
  57.         prtStrAndVal( "a=",  a, NO ); // a => 2 // Impresión del dato de idNm.
  58.         prtStrAndVal( "a=>", a, NL ); // a => 2
  59.  
  60.  
  61.         char b = a + 4; // b := 2+4, b := 6 // Declaración y Asignación de un Nombre Identificador (idNm)
  62.         prtStrAndVal( "b=", b, NL ); // b => 6 // Impresión del dato o valor del idNm
  63.  
  64.         printStr( "Identificador Constante:", PS );
  65.         char const kA = 2; // lock kA := 2 // Declaración y Asignación de un Nombre Identificador Constante (kIdNm )
  66.         prtStrAndVal( "kA=", kA, NL ); // kA => 2
  67.         //kA = 7;
  68.         //prtStrAndVal( "kA=>", kA, NL ); // kA => 7
  69.         // Descomentar las 2 lineas anteriores para verificar que no se puede reescribir
  70.  
  71.         const char kA1 = 2;
  72.         prtStrAndVal( "kA1=", kA1, NL ); // kA1 => 2
  73.         //kA1 = 55;
  74.         //prtStrAndVal( "kA1=>", kA1, NL ); // kA1 => 55
  75.         // Descomentar las 2 lineas anteriores para verificar que no se puede reescribir
  76.  
  77.         // En el encabezado se definio noConst como vacio, simplemente como palabra didactica
  78.         //noConst char c = 2; // c := 2 // Declaración y Asignación de un Nombre Identificador No Constante
  79.         //prtStrAndVal( "c=",  c, NO ); // c => 2 // Impresión del dato de idNm.
  80.         // Descomentar las 2 lineas anteriores para ejecutar las sentencias
  81.  
  82.         printStr( "Identificadores Punteros:", NO );
  83.         printStr( "Caso I: Puntero No Constante a Dato No Constante", PS );
  84.  
  85.         printStr( "ptr1:", NL );
  86.         char *p1 = &a; // p1 -> a, a => 2 // Declaración y Asignación de un Nombre Identificador Puntero (pIdNm)
  87.         // p1 apunta a un tipo de dato Byte
  88.         // noConst char *noConst p1 = &a; // La Declaración y Asignación anterior se puede ver como esta
  89.         prtStrAndVal( "->p1=", *p1, NO ); // (->p1 and a) => 2 // 2 es el valor contenido por la direccion final del pIdNm
  90.         prtStrAndVal( "a=", a, NL ); // a => 2 // Prueba del contenido final de la direccion apuntada.
  91.  
  92.  
  93.         printStr( "ptr2:", NL );
  94.         char *p2; // p2 -> ? // Solo Declaración de un Nombre Identificador Puntero (pIdNm)
  95.         p2 = &b;  // p2 -> b, b => 6 // Asignación de una direccion al pIdNm.
  96.         prtStrAndVal( "->p2=", *p2, NO ); // (->p2 and b) => 6
  97.         prtStrAndVal( "b=", b, NL ); // b => 6 // Prueba del contenido final de la direccion apuntada.
  98.  
  99.         p2 = p1; // p2 -> p1, Como p1 -> a entonces p2 -> a, a => 2 // Cambio de dirección de apuntamiento de p2
  100.         prtStrAndVal( "->p1=", *p1, NO ); // (->p1 and ->p2) => 2
  101.         prtStrAndVal( "->p2=", *p2, NO ); // (->p2 and a) => 2
  102.         prtStrAndVal( "a=", a, NL ); // a => 2 // Prueba del contenido final de la direccion apuntada.
  103.  
  104.         *p2 = 4; // p2 -> p1, p1 -> a, a := 4 // Reasignación del contenido de apuntamiento.
  105.         prtStrAndVal( "->p1=", *p1, NO ); // (->p1 and ->p2) => 4
  106.         prtStrAndVal( "->p2=", *p2, NO ); // (->p2 and a) => 4
  107.         prtStrAndVal( "a=", a, NL ); // a => 4 // Prueba del contenido final de la direccion apuntada.
  108.  
  109.         *p2 = *p2 + 3; // p2 -> p1, p1 -> a, a := a + 3: a:= 7
  110.         prtStrAndVal( "->p2=", *p2, NO ); // (->p2 and a) => 7
  111.         prtStrAndVal( "a=", a, NL ); // a => 7 // Prueba del contenido final de la direccion apuntada.
  112.         // Ver otros tipos de operaciones con punteros
  113.  
  114.         printStr( "ptr3:", NL );
  115.         char *p3 = p2; // p3 -> p2 Como p2 -> p1 y p1 -> a,Entonces p3 -> a , a => 7 // Declaración y Asignación de pIdNm
  116.         // char *p3 = &p2; // &p2, No valido. direccion de direccion
  117.         // char *p3 = 0x3F; // En algunos casos es valido
  118.         // Descomentar las 2 lineas anteriores para verificar la sintaxis invalida
  119.         prtStrAndVal( "->p3=", *p3, NO ); // ->p3 and a => 7
  120.         prtStrAndVal( "a=", a, NL ); // a => 7 // Prueba del contenido final de la direccion apuntada.
  121.  
  122.         *p3 = 9; // p3 -> a, a := 9 // Reasignación del contenido del apuntamiento.
  123.         prtStrAndVal( "->p3=", *p3, NO ); // ->p3 => 9
  124.         prtStrAndVal( "a=", a, NL ); // a => 9 // Prueba del contenido final de la direccion apuntada.
  125.  
  126.  
  127.         printStr( "Arreglos:", NL );
  128.         printStr( "Arreglos numericos: 01324, ...", PS );
  129.  
  130.  
  131.         char num[4]= { 19, 12, 13, 14 }; // num0 := 19, num1 := 12, num2 := 13 num3 := 14
  132.         prtStrAndVal( "num[0]=", num[0], NO ); // num[0]=>19 Despliega el contenido del 1er elemento
  133.         prtStrAndVal( "num[1]=", num[1], NO ); // num[1]=>12 Despliega el contenido del 2d0 elemento
  134.         prtStrAndVal( "num[2]=", num[2], NO );  // num[2]=>13 Despliega el contenido del 3er elemento
  135.         prtStrAndVal( "num[3]=", num[3], NL );  // num[3]=>14 Despliega el contenido del 4to elemento
  136.         num[0] = 11; // Reasignación del contenido del primer elemento num[0]
  137.         prtStrAndVal( "num[0]=", num[0], NL ); // num[0]=>11 Despliega el contenido del 1er elemento
  138.  
  139.         // No funciona esto
  140.         //char num2[5]; // Declaracion de un idNm de 5 caracteres consecutivos
  141.         //num2[5] = { 11, 12, 13, 14 }; // d0 := 11, d1 := 12, d2 := 13, d3 := 14
  142.         //Descomentar las 2 lineas anteriores para verificar la sintaxis invalida
  143.  
  144.         p3 = &( num[0] ); // p3 -> num[0], num[0] => 11 // Redireccionamiento de p3 a num[0]
  145.         prtStrAndVal( "->p3=", *p3, NO ); // ->p3 and num[0] => 11
  146.         prtStrAndVal( "num[0]=", num[0], NL ); // num[0] => 11 // Prueba del contenido final de la direccion apuntada.
  147.  
  148.         p3 = num; // == p3 = &( num[0] ) // El nombre de un array es igual a la direc del mismo
  149.         prtStrAndVal( "->p3=", *p3, NO ); // ->p3 and num[0] => 11
  150.         prtStrAndVal( "num[0]=", num[0], NL ); // num[0] => 11 // Prueba del contenido final de la direccion apuntada.
  151.         // La sentencia p3 = num; es equivalente a p3 = &( num[0] );
  152.         printStr( "", NL );
  153.  
  154.         printStr( "Desplazamiento de direccion >>:", PS);
  155.         prtStrAndVal( "->p3=", *p3, NO ); // num[0] => 11
  156.         p3 = p3 + 2; // p3 -> (p3 + 2pos), p3 -> num[ 0+2 ] , p3 -> num[2], num[2] => 13
  157.         prtStrAndVal( "->p3=", *p3, NO ); // num[2] => 13
  158.         prtStrAndVal( "num[2]=", num[2], NL );  // num[2] => 13 // Prueba del contenido final de la direccion apuntada.
  159.  
  160.         //p3 = p3 + 4; // p3 -> p3 + 4pos , p3 -> num[ 0+4 ] , p3 -> num[4] No existe se sale del array, apunta a una dir no calculada por el algoritmo
  161.         //prtStrAndVal( "->p3=", *p3 );
  162.         // Descomentar las 2 lineas anteriores para verificar el desborde de la direccion
  163.  
  164.         prtStrAndVal( "->p3=", *p3, NO ); // num[2] => 13
  165.         b = *p3 + 4; // b := num[2] + 4, b := 13 + 4, b := 17
  166.         prtStrAndVal( "b=", b, NO ); // b => 14
  167.         printStr( "Nota: (p3 + 4) es diferente a (*p3 + 4)", NL );
  168.  
  169.  
  170.         printStr( "Desplazamiento de direccion <<:", PS );
  171.  
  172.         p3 = &( num[2] ); // p3 -> num[2], num[2] => 13 // Redireccionamiento de p3
  173.         prtStrAndVal( "->p3=", *p3, NO ); // num[2] => 13
  174.         p3 = p3 - 1; // p3 -> (p3 - 1pos), p3 -> num[ 2-1 ] , p3 -> num[1], num[1] => 13
  175.         prtStrAndVal( "->p3=", *p3, NO );  // num[1] => 12
  176.         prtStrAndVal( "num[1]=", num[1], NL );  // num[1] => 12 // Prueba del contenido final de la direccion apuntada.
  177.  
  178.         //prtStrAndVal( "->p3=", *p3, NO );  // num[1] => 12
  179.         //p3 = p3 - 2; // p3 -> (p3 - 2pos), p3 -> num[ 1-2 ] , p3 -> num[-1], num[-1] => ?,
  180.         //No existe en el array, apunta a una dir no calculada por el algoritmo
  181.         //prtStrAndVal( "->p3=", *p3, NO );  //  num[-1] => ??
  182.         //prtStrAndVal( "num[0]=", num[-1], NL ); // num[-1] => ?? // Prueba del contenido del puntero
  183.         //Descomentar las 4 lineas anteriores para verificar el desborde de la direccion
  184.  
  185.         prtStrAndVal( "->p3=", *p3, NO );  // num[1] => 12
  186.         b = *p3 - 2; // b := num[1] - 2, b := 12 - 2, b := 10
  187.         prtStrAndVal( "b=", b, NO ); // b => 10
  188.         printStr( "Nota: (p3 - 2) es diferente a (*p3 - 2)", NL );
  189.  
  190.  
  191.         printStr( "Manejo de Identificadores Punteros con Subindices", PS );
  192.  
  193.         p1 = &( num[0] ); // p1 -> num[0], num[0] => 11 // Redireccionamiento de p1
  194.         prtStrAndVal( "->p1=", *p1, NO ); // num[0] and p1 => 11
  195.         p2 = &( p1[0] ); // == p2 = p1 + 0; // p2 -> p1[0], como p1[0] -> num[0], entonces p2 -> num[0]
  196.         prtStrAndVal( "->p2=", *p2, NO ); // num[0] => 11
  197.         p2 = &( p1[3] ); // == p2 = p1 + 3; // p2 -> p1[3], como p1[3] -> num[0+3], entonces p2 -> num[3]
  198.         prtStrAndVal( "->p2=", *p2, NL ); // num[3] => 14
  199.  
  200.         a = p1[0]; // ==   a = *( p1+0 ); // pidNm[ # ] se debe tener mucho cuidado a donde apunta inicialmente
  201.         prtStrAndVal( "a=", a, NO ); // a => 11
  202.  
  203.         a = p1[1]; // == a = *( p1+1 ); // a := num[0+1], a := num[1], a => 12
  204.         prtStrAndVal( "a=", a, NO ); // a => 12
  205.  
  206.         a = p1[2]; // == a = *( p1+2 );
  207.         prtStrAndVal( "a=", a, NL ); // a => 13
  208.  
  209.         a = *(p1+0);
  210.         prtStrAndVal( "a=", a, NO ); // a => 11
  211.  
  212.         a = *(p1+1);
  213.         prtStrAndVal( "a=", a, NO ); // a => 12
  214.  
  215.         a = *(p1+2);
  216.         prtStrAndVal( "a=", a, NL ); // a => 13
  217.  
  218.         p1 = &( num[2] ); // p1 -> num[2], num[2] => 13 // Redireccionamiento de p1
  219.         prtStrAndVal( "->p1=", *p1, 0 ); // num[2] => 13
  220.  
  221.         a = p1[-1]; // == a = *( p1-1 ); // a := num[2-1], a := num[1], a => 12
  222.         prtStrAndVal( "a=", a, NO ); // a => 12 // Coincide con el calculo anterior
  223.  
  224.         a = p1[-2]; // == a = *(p1-2); // a := num[2-2], a := num[2], a => 11
  225.         prtStrAndVal( "a=", a, NO ); // a => 11 // Coincide con el calculo anterior
  226.  
  227.         //a = p1[-3]; // == a = *(p1-3); // a := num[2-3], a := num[-1], num[-1]=??
  228.         //prtStrAndVal( "a=", a, NO ); // a => ? // Imprime un valor basura
  229.         // Descomentar las 2 lineas anteriores para verificarlo
  230.  
  231.         prtStrAndVal( "->p1=", *p1, 0 ); // num[2] => 13
  232.         a = *(p1-1);
  233.         prtStrAndVal( "a=", a, NO ); // a => 12
  234.  
  235.         a = *(p1-2);
  236.         prtStrAndVal( "a=", a, NL ); // a => 11
  237.  
  238.         //a = *(p1-3);
  239.         //prtStrAndVal( "a=", a, NL ); a => ? // Imprime un valor basura
  240.         // Descomentar las 2 lineas anteriores para verificarlo
  241.  
  242.  
  243.         printStr( "Manejo de Arrays como Punteros", PS );
  244.  
  245.         // char num[3]= { 20, 55, 87 }; // num0 := 20, num1 := 55, c3 := 87
  246.         *(num+0) = 20; // ==  num[0] = 20;
  247.         prtStrAndVal( "num[0]=", num[0], NO );
  248.  
  249.         *(num+1) = 55; //
  250.         prtStrAndVal( "num[1]=", num[1], NO );
  251.  
  252.         *(num+2) = 87; //
  253.         prtStrAndVal( "num[2]=", num[2], PS );
  254.         printStr( "", NL );
  255.  
  256.         printStr( "Desplazamiento de Direccion Formato Simplificado ver def", PS );
  257.         // num[3]= { 20, 55, 87 }; // num0 := 20, num1 := 55, c3 := 87
  258.  
  259.         p1 = &( num[0] ); // p1 -> num[0], num[0] => 20 // Re-direccionamiento de p1
  260.         prtStrAndVal( "->p1=", *p1, NL ); // num[0] => 20
  261.  
  262.         printStr( "++ como prefijo", NL );
  263.  
  264.         p2 = ++p1; // p2 -> p1, pero efectúa dos operaciones, primero preincrementa el
  265.         // apuntamiento de p1 asi: p1 = p1 + 1; (P1 -> num[0+1]) luego redirecciona p2: p2 = p1;// P2 -> num[1]
  266.         prtStrAndVal( "->p1=", *p1, NO ); // num[1] => 55
  267.         prtStrAndVal( "->p2=", *p2, NO ); // num[1] => 55
  268.         prtStrAndVal( "num[1]=", num[1], NO ); // num[1] => 55
  269.         printStr( "Note que tanto p1 como p2 apuntan a la misma direccion num[1]", PS );
  270.  
  271.         printStr( "", NL);
  272.         printStr( "++ como postfijo", NL);
  273.         p1 = &( num[0] ); // p1 -> num[0], num[0] => 20 // Re-direccionamiento de p1
  274.         prtStrAndVal( "->p1=", *p1, 0 ); // num[0] => 20
  275.         p2 = p1++; // p2 -> p1, pero efectúa dos operaciones, primero redirecciona p2: p2 = p1;// P2 -> num[0]
  276.         // luego posincrementa el apuntamiento de p1 asi: p1 = p1 + 1; (P1 -> num[0+1]) luego
  277.         prtStrAndVal( "->p1=", *p1, NO ); // num[1] => 55
  278.         prtStrAndVal( "->p2=", *p2, NO ); // num[0] => 20
  279.         printStr( "Note que tanto p1 como p2 NO apuntan a la misma direccion", PS );
  280.  
  281.         printStr( "Llamada con ++ como prefijo", PS );
  282.         p1 = &( num[0] );
  283.         prtStrAndVal( "->p1=", *p1, NO ); // num[0] => 20
  284.         char c = *( ++p1 ); // Primero preincrementa el apuntamiento de p1 asi: p1 = p1 + 1; (P1 -> num[0+1]) P1 -> num[1]
  285.         //luego asigna a c: c = *p1; // P1 -> num[1]
  286.         prtStrAndVal( "->p1=", *p1, NO ); // num[1] => 55
  287.         prtStrAndVal( "  c=", c, PS ); // num[1] => 55
  288.  
  289.         printStr( "Llamada con ++ como posfijo", PS );
  290.         p1 = &( num[0] );
  291.         prtStrAndVal( "->p1=", *p1, NO ); // num[0] => 20
  292.         c = *( p1++ ); // Primero asigna a c: c = *p1; // P1 -> num[0] // Luego
  293.         // postincrementa el apuntamiento de p1 asi: p1 = p1 + 1; (P1 -> num[0+1]) P1 -> num[1]
  294.         prtStrAndVal( "->p1=", *p1, NO ); // num[1] => 55
  295.         prtStrAndVal( "  c=", c, NO ); // num[0] => 20
  296.  
  297.         printStr( "Analogamente con -- como pos/prefijo", PS );
  298.  
  299.         printStr( "Punteros como Argumento de Funciones", PS);
  300.  
  301.  
  302.         printStr( "Utilizando como ejp la funcion: void fnt1_val( char *p1_fnt1_val ){ ... }" , NL );
  303.         printStr( "Pensar como una sola sentencia: char *p1_fnt1_val = &( num[0] );", NL);
  304.         fnt1_val( &( num[0] ) ); // Llamada de la funcion con el argumento "&( num[0] )"
  305.  
  306.         // *p1_fnt1_val = &( num[0] ); // Transfiere la direccion contenida por Array posicion valor (0) en el pIdNm (p1_fnt1)
  307.         prtStrAndVal( "num[0]=", num[0], NL ); // num[1] => 20
  308.  
  309.  
  310.         printStr( "Utilizando como ejp la funcion: void printStr( const char kStr[], char TypePrint){ cout << Str << endl; ... }" , PS );
  311.  
  312.         printStr( "Pensar como una sola sentencia: const char kStr[] = ''Hola'';   char TypePrint = NL;", NL);
  313.         printStr( "los objetos temporales y/o literales debeb ser const", PS );
  314.  
  315.  
  316.  
  317.         printStr( "Punteros como Argumento de Estructuras", PS );
  318.  
  319.         struct strc1_3elements strc1_ElementX; // Define el id strc1_ElementX de tipo estructura de elementos de nombre strc1_3elements
  320.  
  321.         strc1_ElementX.SubElm1_Byte = 99;
  322.         strc1_ElementX.SubElm2_Int = 88;
  323.         *(strc1_ElementX).SubElm3_Array4Elm = "Hello3";
  324.  
  325.         //cout <<  "strc1_ElementX.SubElm1_Byte=" << ((strc1_ElementX).SubElm1_Byte)+0 << endl;
  326.  
  327.         prtStrAndVal( "strc1_ElementX.1=", strc1_ElementX.SubElm1_Byte, NO );
  328.         prtStrAndVal( "strc1_ElementX.2=", strc1_ElementX.SubElm2_Int, NO );
  329.         //printStrVal3( "strc1_ElementX.3=", (*strc1_ElementX).SubElm3_Array4Elm, NO );
  330.  
  331.  
  332.         printStr( "Punteros de Cadena de Caracteres", NL );
  333.  
  334.         printStr( "Arreglo Caracteres 'A','B','C'...'1','2','3','@', '#'...", PS );
  335.         // Un caracteres se codifica entre comillas simple 'H' y se usa en este tutorial la funcion de impresion prtStrAndVal()
  336.         // y una cadena de caractres entre comillas dobles "Hello" y se usa en este tutorial la funcion de impresion printStr()
  337.         // Cada caracter tiene asociado un valor numerico entre 64 y 256
  338.         // En una cadena o arreglo de caracteres estos se toman como un conjunto de constantes de numeros
  339.  
  340.         char str1[ 4 ] = "ABC"; // Define e inicializa un identificador que contiene un
  341.         //arreglo de 4 caracteres constantes "ABC+Nulo", el caracter nulo '\0' no se incluye en la definicion.
  342.         // Se puede obviar la definicion de la cantidad de los elementos del arreglo asi:
  343.         // char str1[] = "ABC"; // == // char str1[ 4 ] = "ABC";
  344.  
  345.         // Si se incluye el caracter nulo '\0' el arreglo que da como "ABC\0\0"
  346.         // char str1_[ 4 ] = "ABC\0";  // == "ABC\0\0"
  347.  
  348.         //char str0[ 4 ];
  349.         //str0[4] = "ABC"';
  350.         //Descomentar las 2 lineas anterior para verificar QUE NO SE PUEDE primero declarar y luego asignar la cadena.
  351.         //pero por que si funciona en funcion
  352.  
  353.         prtStr1And2( "str1=", str1, NL ); // str1 => "ABC" // El caracter nulo no se visualiza
  354.  
  355.         prtStr1And2( "str1=", &str1[0], NO ); // str1 => "ABC"
  356.         prtStr1And2( "str1=", &str1[1], NO ); // str1 => "BC"
  357.         prtStr1And2( "str1=", &str1[2], NO ); // str1 => "C"
  358.         prtStr1And2( "str1=", &str1[3], PS ); // str1 => "" // Nulo
  359.         printStr( "", NL );
  360.  
  361.         str1[0] = 'a'; // Reescribiendo la 1er posicion de la cadena de caracteres (Cambio a minuscula)
  362.         prtStr1And2( "str1=", str1, NL ); // str1 => "aBC"
  363.  
  364.         str1[1] = 'b'; // Reescribiendo la 2da posicion de la cadena de caracteres (Cambio a minuscula)
  365.         str1[2] = '7'; // Reescribiendo la 3 posicion de la cadena de caracteres (Cambio de caracter)
  366.         prtStr1And2( "str1=", str1, NL ); // str1 => "ab8"
  367.  
  368.         str1[0] = 'efg'; // Solo toma el 1er byte de derecha a izquierda ('efg') por que la definicon del idNm
  369.         // es de 1 Byte (char) // Se genra una advertencia de multiples caracteres o perdida de informacion
  370.         prtStr1And2( "str1=", str1, NL ); // str1 => "gb8"
  371.  
  372.         printStr( "Otra definicion para Arreglo de Caracteres", NL );
  373.         char str2[ 4 ] = { 'A', 'B', '7', '\0' }; // define e inicializa un identificador que contiene
  374.         // un arreglo de 4 caracteres ABCD+Nulo, como lista de caracteres si se debe incluir '\0'
  375.         prtStr1And2( "str2=", str2, NO ); //  str1 => "ABC"
  376.         prtStr1And2( "str2=", &str2[0], NO ); // str2 => "AB7"
  377.         prtStr1And2( "str2=", &str2[1], NO ); // str2 => "B7"
  378.         prtStr1And2( "str2=", &str2[2], NO ); // str2 => "7"
  379.         prtStr1And2( "str2=", &str2[3], PS ); // str2 => "" // Nulo
  380.         //prtStr1And2( "str2=", &str2[4], NO ); // str1 => ? // No existe la posicion 4
  381.         // Descomentar la linea anterior para verificar el Bug
  382.  
  383.         printStr( "", NL );
  384.         char Str3[ 3 ] = "xy"; // Define e inicializa un identificador que contiene
  385.         // un arreglo de 3 caracteres xy+Nulo
  386.  
  387.         char *p4 = &( Str3[0] ); // Define un identificador puntero que apunta al identificador Str3,
  388.         // Nota: El nombre de una cadena es igual a la direccion inicial del mismo
  389.         // char *p4 = Str3; // == // char *p4 = &( Str3[0] );
  390.         prtStr1And2( "str3=", p4, NL ); // str3 => "xy"
  391.  
  392.         //  Cuando se separa se requiere predefinirlo como connstante
  393.  
  394.         const char *p5; // Solo Declaración de un Nombre Identificador Puntero (pIdNm)
  395.         p5 = "xy"; // Asigna la dirección de "xy" a p5 donde "xy" fue almacenado en una posicion de memoria
  396.         prtStr1And2( "->p5=", p5, NL ); // str3 => "xy"
  397.  
  398.         // Pero no funciona esto
  399.         //char *p5;
  400.         //p5 = { 'x', 'y' }; // asigna la dirección de "xy", Duda: "xy" es igual a { 'x', 'x' }?
  401.  
  402.  
  403.  
  404.         printStr( "Caso II: Puntero No Constante (Redireccionable) a Dato Constante (const char) (NO reescribible)",  PS );
  405.         // Sirve por ejemplo para transferir informacion y que esta no se reescriba (solo lectura)
  406.  
  407.         char strn[] = "Enter Equation:";
  408.         const char *pStrn_kD; // Caso 2: Declaracion de un Puntero No Constante (Redireccionable)
  409.         // a Dato Constante (const char) (NO reescribible)
  410.  
  411.         pStrn_kD = &( strn[0] ); // dir de "Enter Equation:" posicion inicial "E"
  412.         prtStr1And2( "->pStrn_kD=", pStrn_kD, NL ); //  => "Enter equation:"
  413.         //*pStrn_kD = 'e'; // reaccionacion del contenido // pStrn_kD es solo de lectura
  414.         // Descomentar la linea anterior para verificar QUE NO SE PUEDE modificar el contenido
  415.         // de la direccion apuntada por ser un dato constante
  416.  
  417.         pStrn_kD = &( strn[6] ); // Pero si se puede redireccionar un ptr no constante.
  418.         prtStr1And2( "->pStrn_kD=", pStrn_kD, NL ); // => "Equation:"
  419.  
  420.  
  421.         ////////////////
  422.         printStr( "Caso III: Puntero Constante (NO Redireccionable) (*const pkStrn2) a Dato No Constante (Reescribible)",  PS );
  423.         // Sirve por ejemplo para transferir informacion y que esta no se reescriba (solo lectura)
  424.  
  425.         char strn2[] = "X > -3";
  426.         char *const pKStrn2 = &( strn2[0] ); // Decl y asig de un Puntero Constante (NO Redireccionable) (*const pkStrn2)
  427.         //a Dato No Constante (Reescribible) // OJO Se requiere definirlo en la declaracion
  428.  
  429.         //char *const pKStrn2;
  430.         //pKStrn2 = &( strn2[0] );
  431.         //Descomentar las 2 lineas anterior para verificar QUE NO SE PUEDE primero declarar y luego asignar la dir.
  432.  
  433.         prtStr1And2( "->pKStrn2= ", pKStrn2, NL ); //  => "Solution is := X > -3"
  434.  
  435.         //pKStrn2 = &( strn2[2] ); // No se puede redireccionar un ptr Constante.
  436.         //prtStr1And2( "->pKStrn2=", pKStrn2, NL ); //  => "Equation:"
  437.         // Descomentar las 2 lineas anterior para verificar QUE NO SE PUEDE redireccionar
  438.  
  439.         //char y = '9';
  440.         //pKStrn2 = &( y ); // No debe dejar redireccionar
  441.         //Descomentar las 2 lineas anteriores para verificar QUE NO SE PUEDE redireccionar
  442.  
  443.         *pKStrn2 = 'Y'; // SI SE PUEDE modificar el contenido de la direccion apuntada por ser un dato No constante
  444.         prtStr1And2( "->pKStrn2= ", pKStrn2, NL ); //  => "Enter equation:"
  445.  
  446.  
  447.  
  448.         printStr( "Caso IV: Puntero Constante (*const pkArray1) a Dato Constante (const char)",  PS );
  449.         prtStr1And2( "", "", NL );
  450.  
  451.         char array1[] = { 'A', 9, '9' };
  452.         const char *const pKArray1 = &( array1[0] );  // Decl y asig de un Puntero Constante (NO Redireccionable) (*const pkStrn2)
  453.         //a Dato Constante (No Reescribible) // OJO Se requiere definirlo en la declaracion
  454.  
  455.         //const char *const pKArray1;
  456.         //pKArray1 = &( array1[0] );
  457.         //Descomentar las 2 lineas anterior para verificar QUE NO SE PUEDE primero declarar y luego asignar la dir.
  458.  
  459.         prtStrAndChr("->pStr= ", pKArray1[0], NO ); // => 'A'
  460.         prtStrAndVal("->pStr= ", pKArray1[1], NO ); // => 9
  461.         prtStrAndChr("->pStr= ", pKArray1[2], NO ); // => '9'
  462.  
  463.         //pKArray1 = &( array1[1] ); // No se puede redireccionar
  464.         //prtStrAndChr("->pStr= ", pKArray1[1], NO );
  465.         //Descomentar las 2 lineas anteriores para verificar QUE NO SE PUEDE redireccionar
  466.  
  467.         //pKArray1 = 'e'; // o se puede redireccionar
  468.         //prtStrAndChr("->pStr= ", pKArray1[1], NO );
  469.         //Descomentar las 2 lineas anteriores para verificar QUE NO SE PUEDE redireccionar
  470.  
  471.         printStr( " ", PS );
  472.        
  473.         fnt1_str( "Hello", 5 ); // Imprime caracter por caracter
  474.  
  475.         printStr( " ", NL );
  476.         printStr( "Valor referencia", NL );
  477.  
  478.         // Escribiendo ...
  479.         return 0;
  480. }
  481.  
  482.  
  483.  
  484. void fnt1_val( char *p1_fnt1_val ){ // *p1_fnt1_val = &( num[0] );
  485.         prtStrAndVal( "->p1_fnt1_val=", *p1_fnt1_val, NO ); // Imprime valor
  486. };
  487.  
  488. void fnt1_str( const char *p1_fnt1_str, char SizeFlag ){ // *p1_fnt1_str = "...";
  489.         for( char CounterPtr = 0; CounterPtr <= SizeFlag-1; CounterPtr++ ){
  490.                 prtStrAndChr( "->p1_fnt1_str=", *( p1_fnt1_str+CounterPtr ), PS ); // Imprime caracter * caracter
  491.                 //PAUSAR;
  492.         }
  493. };
  494.  
  495.  
  496.  
  497.  
  498. // Funciones para Imprimir
  499.  
  500. void printStr( const char kStr[], char TypePrint){ // Impresion de una cadena
  501.         cout << kStr << endl;
  502.         if( TypePrint == NL ){
  503.                 cout<<"\n";
  504.         }
  505.         else
  506.                 if( TypePrint == PS && Flag_Pausar == 1 ){
  507.                         cout<<"\n"; PAUSAR; cout<<"\n";
  508.                 }
  509.                 else
  510.                         if( TypePrint == NO ){
  511.                         }
  512.                         //ifend
  513.                 //ifend
  514.         //ifend
  515. }
  516.  
  517. void prtStrAndVal( const char kStr[], char Value, char TypePrint){ // Impresion de una cadena y de un valor numerico
  518.         cout << kStr << Value+0 << endl;
  519.         if( TypePrint == NL ){
  520.                 cout<<"\n";
  521.         }
  522.         else
  523.                 if( TypePrint == PS && Flag_Pausar == 1 ){
  524.                         cout<<"\n"; PAUSAR; cout<<"\n";
  525.                 }
  526.                 else
  527.                         if( TypePrint == NO ){
  528.  
  529.                         }
  530.                         //ifend
  531.                 //ifend
  532.         //ifend
  533. }
  534.  
  535. void prtStrAndChr( const char kStr[], char Value, char TypePrint){ // Impresion de una cadena y de 1 caracter
  536.         cout << kStr << Value << endl;
  537.         if( TypePrint == NL ){
  538.                 cout<<"\n";
  539.         }
  540.         else
  541.                 if( TypePrint == PS && Flag_Pausar == 1 ){
  542.                         cout<<"\n"; PAUSAR; cout<<"\n";
  543.                 }
  544.                 else
  545.                         if( TypePrint == NO ){
  546.  
  547.                         }
  548.                         //ifend
  549.                 //ifend
  550.         //ifend
  551. }
  552.  
  553. void prtStr1And2( const char kStr[], const char k2Str[], char TypePrint){ // Impresion de 2 cadenas
  554.         cout << kStr << k2Str << endl;
  555.         if( TypePrint == NL ){
  556.                 cout<<"\n";
  557.         }
  558.         else
  559.                 if( TypePrint == PS && Flag_Pausar == 1 ){
  560.                         cout<<"\n"; PAUSAR; cout<<"\n";
  561.                 }
  562.                 else
  563.                         if( TypePrint == NO ){
  564.  
  565.                         }
  566.                         //ifend
  567.                 //ifend
  568.         //ifend
  569. }
  570.  
  571.  
  572.  
  573.  
  574. void printStrVal3( strc1_3elements X, char TypePrint){
  575.         //cout << X << endl;
  576.         if( TypePrint== NL ){
  577.                 cout<<"\n";
  578.         }
  579.         else
  580.                 if( TypePrint == PS && Flag_Pausar == 1 ){
  581.                         cout<<"\n"; PAUSAR; cout<<"\n";
  582.                 }
  583.                 else
  584.                         if( TypePrint== NO ){
  585.  
  586.                         }
  587.                         //ifend
  588.                 //ifend
  589.         //ifend
  590. }
  591.  
  592.  
  593. //struct strc1_3elements{
  594. //  char SubElm1_Byte; // SubElemento1 tipo char
  595. //  int  SubElm2_Int; // SubElemento2 tipo Integer
  596. //  char *SubElm3_Array4Elm[ 2 ]; // SubElemento3 tipo char de 2 subelementos (Array)
  597. //};
« Última modificación: 06 de Diciembre de 2012, 14:51:48 por CompSystems »
Desde Colombia

Desconectado jukinch

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 608
Re: Guía definitiva de Manejo Punteros en C/C++
« Respuesta #1 en: 09 de Noviembre de 2012, 18:13:34 »
Hola CompSystems:
                    Ya guardé el ejemplo para estudiarlo sin prisa y tranquilo.
                     Gracias por compartir. :)
                            Saludos.
                                  Jukinch
"Divide las dificultades que examinas en tantas partes como sea posible para su mejor solución." -René Descartes

Desconectado CompSystems

  • PIC18
  • ****
  • Mensajes: 488
    • Home Page
Re: Guía definitiva de Manejo Punteros en C/C++
« Respuesta #2 en: 27 de Noviembre de 2012, 19:57:10 »
Actualice en el 1er post el archivo ejemplo con mas ejercicios (0.07, 06 Dic 2012), por fin entendí la verdadera utilidad de la palabra clave CONST

Nota: Modificar la definición (Flag_Pausar) para pausar o no por partes la secuencia de los ejercicios del ejemplo  

Código: C++
  1. #define Flag_Pausar 1 // Cambiar 1 para activar las Pausas, 0 para No Pausar

Si se define Flag_Pausar como 0 entonces se puede incluir dentro del código la instrucción (PAUSAR;) para detener el programa en un lugar especifico determinado por el usuario

PD: Incorporando ejercicios con estructuras ...
« Última modificación: 06 de Diciembre de 2012, 14:52:39 por CompSystems »
Desde Colombia

Desconectado CompSystems

  • PIC18
  • ****
  • Mensajes: 488
    • Home Page
Re: Guía definitiva de Manejo Punteros en C/C++
« Respuesta #3 en: 10 de Mayo de 2013, 00:29:53 »
Desde Colombia