Autor Tema: Como Leer punteros - Tutorial  (Leído 10234 veces)

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

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #15 en: 19 de Abril de 2016, 13:43:57 »
Código: C
  1. int array[10]{0,10,20,33,44,55,66,77,88,99}
  2.  
  3. int (*p)=array

//si modifico p=3; ¿¿cuando lo lea me dara 33??

No... lo que vos estas haciendo es decir que p es un puntero a un int, luego le asignas la direccion de array a p.

En memoria array[10] no es nada mas que 10 posiciones de memoria. Suponete que es una memoria lineal y que int es de 8 bits. Ademas esta ubicado en la direccion 0x10.

Código: [Seleccionar]
Direccion : Contenido
0x10 : 0         Array[0]
0x11 : 10       Array[1]
0x12 : 20       Array[2]
0x13 : 33       Array[3]
0x14 : 44       Array[4]
0x15 : 55       Array[5]
0x16 : 66       Array[6]
0x17 : 77       Array[7]
0x18 : 88       Array[8]
0x19 : 99       Array[9]

Cuando vos haces:

Código: [Seleccionar]
p = array;           // Esto es identico a p = &array[0]
Lo que estas haciendo es que p va a tener el valor de la direccion inicial de array, es decir p = 0x10;

Si haces p = 3, lo unico que harias es apuntar a la direccion de memoria 0x03. Lo cual no sabes que hay en este caso.

Cuando usas *p , lo que hace es acceder a la direccion de memoria que contiene p, es decir si p es 0x15, y vos haces *p=10 , seria equivalente que hacer array[5] = 10; es decir poner el 10 en la direccion 0x15

Los punteros es lo mejor de C y lo mas dificil de entender y aprender a usarlos tambien. Nuevamente este tutorial no era para "aprender" sobre los mismos, sino unicamente a aprender a leerlos. De necesitar aprender sobre los mismos recomiendo ir a buscar un tutorial por internet. Que hay de sobra.

Espero haber respondido tu pregunta.

Una sola cosa mas.. yo aca asumi que el puntero es de 8 bits. Pero el puntero esta dado por la arquitectura del micro y el compilador. No hay un tamaño fijo. Si ves un cast a un puntero, no significa que le esten cambiando el tamaño al mismo, sino el tamaño de lo que apunta.

Desconectado Carlos2302

  • PIC16
  • ***
  • Mensajes: 110
Re:Como Leer punteros - Tutorial
« Respuesta #16 en: 01 de Mayo de 2016, 19:49:28 »
Gracias amigo KILLERJC muy buen aporte, en mi caso me gustaria un tutorial sobre la estructura de datos en los microprocesadores. Si puedes hacer se agradece. Por ejemplo los typedef struct.
Gracias a Dios por aquellas personas que ayudan sin esperar nada a cambio. Dios los bendiga hoy mañana y siempre.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #17 en: 02 de Mayo de 2016, 07:50:28 »
Gracias amigo KILLERJC muy buen aporte, en mi caso me gustaria un tutorial sobre la estructura de datos en los microprocesadores. Si puedes hacer se agradece. Por ejemplo los typedef struct.

Cuando dijiste estructuras de datos en microcontrolador pense en cualquier otra cosa menos en las estructuras en C.

typedef struct

Son 2 cosas distintas. Un struct es muy simple de entender es como una variable con varias componentes, nada mas. El struct tiene estas partes:

Código: C
  1. struct tag_name {
  2.    tipo miembro1;
  3.    tipo miembro2;
  4. };

struct para indicarle a C de lo que se trata, tag_name para darle un nombre a esa definicion.

Código: C
  1. struct account {
  2.    int account_number;
  3.    char *first_name;
  4.    char *last_name;
  5.    float balance;
  6. };

Ejemplo ahi la estructura tiene varios contenidos, como numero de cuenta, nombre, apellido y finalmente el balance ( dinero ). Utilizar esto es simple, lo que hay que entender que una estructura NO es algo que ocupe espacio (lo de arriba no ocupa espacio), no lo hace hasta que no se lo asigna a algo, pensalo como si fuera solo un formato (definicion ). Ejemplo si hacemos:

Código: C
  1. struct account Micuenta;

Ahora si Micuenta, va a ocupar el espacio que debe, es decir el espacio de 2 punteros + un float + un int. Como decia utilizarlo es simple

Código: C
  1. char nombre[10]="Ramiro"
  2. char Apellido[10]="Gonzales"
  3.  
  4. struct account Micuenta;
  5. struct account SegundaCuenta;
  6.  
  7. Micuenta.account_number=1;
  8. Micuenta.first_name = nombre;
  9. Micuenta.last_name = Apellido;
  10. Micuenta.balance = -1;                  // Bancarrota total
  11.  
  12. // Segunda cuenta posee el mismo formato que Micuenta, es decir tiene los 2 punteros + floa + int, pero es de el
  13. SegundaCuenta.account_number=2;

Si quisieramos acceder al valor del puntero. Supongamos que tengamos este estructura

Código: C
  1. typedef struct list_element list_element;
  2. struct list_element {
  3.    int p;
  4.    list_element * next;
  5. };
  6.  
  7. list_element el = { .p = 10 };
  8. list_element le = { .p = 50, .next = &el };

Es decir "le" apunta a "el" , yo podria acceder a p por ejemplo de "el" a traves de "le". De esta forma

Código: C
  1. le.next->p = 4;
  2. //o es lo mismo que hacer:
  3. le.*next.p = 4;

Y ahi cambiaria el p de "el" por 4 desde el puntero de "le"

Cosas pendientes:

- Declaracion de struct en la misma definicion
- Por que usar typedef, o cuando debo usarlo
- Por que use typedef en el ejemplo anterior.


PD: Aunque no se por que lo explico ya que esta todo en ejemplos:

http://www.tutorialspoint.com/cprogramming/c_structures.htm
« Última modificación: 02 de Mayo de 2016, 07:59:27 por KILLERJC »

Desconectado Carlos2302

  • PIC16
  • ***
  • Mensajes: 110
Re:Como Leer punteros - Tutorial
« Respuesta #18 en: 02 de Mayo de 2016, 17:24:38 »
Gracias Genio. Pero esto struct account Micuenta;  es como si fuera una instancia de esto.

struct account {
   int account_number;
   char *first_name;
   char *last_name;
   float balance;
};

Gracias por la pagina no la conocia.
« Última modificación: 02 de Mayo de 2016, 18:24:14 por Carlos2302 »
Gracias a Dios por aquellas personas que ayudan sin esperar nada a cambio. Dios los bendiga hoy mañana y siempre.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #19 en: 02 de Mayo de 2016, 23:07:38 »
Termino el tema un poco rapido por falta de tiempo..

Al definir

Código: C
  1. struct account Micuenta;

Le estoy diciendo que "Micuenta" tiene el formato de la estructura "account", es en ese momento que realmente estoy definiendo mi variable ( la que ocupa espacio de memoria), antes solo defini como estaria formado ( el formato, la definicion, como quieras llamarle) pero que si esta y yo no creo ninguna variable eso no va a ocupar espacio en memoria. Algunas veces muchos declaran la variable en el mismo lugar donde definen la estructura.

Código: C
  1. struct account {
  2.    int account_number;
  3.    char *first_name;
  4.    char *last_name;
  5.    float balance;
  6. } Micuenta, SegundaCuenta;

Es totalmente valido. Y es lo unico que me quedaba de estructuras, estan los bit fields pero que puede llevar a errores de portabilidad por que no siempre se respeta el orden, ya que el standard de C no dice nada y queda libre a el compilador.

Por que usar typedef ?

typedef es para crear un tipo de variable (una traduccion seria "definir un nuevo tipo"). Asi como tenemos int, char, bool, podemos crear una variable.
El formato es :

typedef origen destino;

Código: C
  1. typedef int MiEntero;

Y tranquilamente podria hacer:

Código: C
  1. MiEntero MiVariable;

Por lo cual MiVariable es del tipo "MiEntero", ( aunque en este caso sea lo mismo que poner int, pero hay mas complicadas)

Ahora veamos un caso con estructuras, donde tenemos funciones que devuelven estructuras, pasan argumentos con estructuras, etc.

Código: C
  1. struct MyStruct {
  2.          elemento 1;
  3.          elemento 2;
  4. };
  5.  
  6. struct MyStruct FuncionNumero1(int valor, struct MyStruct EstructuraRecibida)
  7. {
  8.       struct MyStruct NuevaEstructura;
  9.       .....;
  10. }

Como que tenemos que escribir siempre struct MyStruct, ahora si definimos un tipo nuevo. Digamos que le damos el nombre "MyStruct_t" ( la t de tipo ) se vuelve mas facil trabajar con estas

Código: C
  1. struct MyStruct {
  2.          elemento 1;
  3.          elemento 2;
  4. };
  5.  
  6. typedef struct MyStruct MyStruct_t;
  7.  
  8. MyStruct_t FuncionNumero1(int valor, MyStruct_t EstructuraRecibida)
  9. {
  10.       MyStruct_t NuevaEstructura;
  11.       .....;
  12. }

Pero este no es el unico caso, como decia en el ultimo ejemplo de mi anterior post se uso, pero no con ese motivo. Sino otro.

Código: C
  1. typedef struct list_element list_element;
  2. struct list_element {
  3.    int p;
  4.    list_element * next;
  5. };

Lo primero a observar es que el tag_name ( o identificador de la estructura: list_element ) puede usarse el mismo texto como un tipo, y no produciria ningun error, por eso los nombres son iguales en el typedef de este ejemplo. es decir typedef struct list_element list_element; estoy diciendo que cree un nuevo tipo llamado list_element ( el ultimo ) y que sea igual a "struct list_element" ( struct + tag_name de la estructura )

Segundo, Si hacemos una estructura, que adentro debe poseer la misma estructura tendriamos un error, me refiero a estar parte unica del codigo sin el typedef:

Código: C
  1. struct list_element {
  2.    int p;
  3.    list_element * next;
  4. };

, por que en ese momento todavia no esta la definicion completa de la estructura (y no existe list_element per se ), existen 2 formas de hacerlo si no mal recuerdo ( que hace mucho que no lo uso). La primera es declarar la estructura primero, asi "existe" por mas que no le digamos que tiene dentro o como esta formada.

Código: C
  1. struct list_element;
  2. struct list_element {
  3.    int p;
  4.    struct list_element * next;
  5. };

La segunda es definir un tipo, que es el caso del codigo de ejemplo, se observa que tanto el struct list_element, como la creacion del tipo por el typedef no generar error a pesar de estar sus definiciones "vacias".

Hay mas cosas sobre las estructuras. Como por ejemplo uno asume muchas veces que los datos estan todos seguidos, y vas a ver gente creando codigo en el cual acceden a las estructuras con punteros a 8bits por ejemplo. Esto no trae ningun problema en un micro de 8 bits. El problema pasa cuando te vas a otro de 16bits. C te asegura que el orden de los elementos sea igual que los escribiste, PERO, no te asegura que van a estar contiguos, sino que los va a acomodar como a el le guste, y por ejemplo en un micro de 8 bits que te podia ocupar 40bytes tu estructura, en un micro de 16 bits tal ves ocupe 44 bytes, donde esos 4 que se agregan es lo que se llama padding. Es lo unico a remarcar creo.

Respecto a los typedef, una recomendacion es NO usar typedef con punteros!. Ya que ocultan al programar el mismo, es decir:

Código: C
  1. typedef *int MiPEntero;
  2.  
  3. MiPEntero Myptr;

Si uno lee, aunque aca esta muy claro, pero en un archivo medio grande la definicion de los typedef quedan escondidos o son pocos visibles, si alguien encuentra eso en el codigo, pensara que es un variable mas, pero que en realidad es un puntero, eso se intenta evitar de hacer, aunque el ejemplo no tiene sentido, se podria aplicar por ejemplo a un puntero de una estructura.
« Última modificación: 02 de Mayo de 2016, 23:17:18 por KILLERJC »

Desconectado marvicdigital

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 311
Re:Como Leer punteros - Tutorial
« Respuesta #20 en: 15 de Agosto de 2018, 17:15:31 »
Hola a todos. Killer muchas gracias por tu buen tutorial....me está sirviendo mucho, aunque tengo una inquietud sobre el tema de usar un apuntador a una estructura..pero una estructura formada por variables fijadas a cierta cantidad de bits..voy a escribir parte del código de un ejemplo simple de un contador de cuatro dígitos:
Código: C
  1. struct{
  2.  
  3.           unsigned char Unidad : 4;
  4.           unsigned char Decena : 4;
  5.           unsigned char Centena : 4;
  6.           unsigned char Miles : 4;
  7.  
  8. }volatile digitos;


Como uso varias interrupciones pues por eso lo pongo volatile..la pregunta es :puedo usar punteros para las variables que están dentro de la estructura asi sean de 4 bits solamente?..el código lo estoy usando para Atmega. aunque para esto no creo que eso importe mucho.

Gracias y saludos
« Última modificación: 15 de Agosto de 2018, 17:18:22 por marvicdigital »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #21 en: 15 de Agosto de 2018, 18:35:28 »
No, podes hacer un puntero a la estructura y de alli acceder a los elementos, pero no podes hacer un puntero a cada bitfield.

La razon es obvia una ves que sabes que el puntero es unicamente la direccion que ocupa la variable..

 Supongamos que son 4 bits, y en una sola posicion de memoria ( 0x100 ), tenes tanto Unidad como Decena. Seria imposible discriminar cual es cual, ya que la minima medida que abarca el  puntero son 8 bytes. ambos punteros tendrian la misma direccion de memoria 0x100 y 0x100

Desconectado marvicdigital

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 311
Re:Como Leer punteros - Tutorial
« Respuesta #22 en: 15 de Agosto de 2018, 19:10:32 »
No, podes hacer un puntero a la estructura y de alli acceder a los elementos, pero no podes hacer un puntero a cada bitfield.

La razon es obvia una ves que sabes que el puntero es unicamente la direccion que ocupa la variable..

 Supongamos que son 4 bits, y en una sola posicion de memoria ( 0x100 ), tenes tanto Unidad como Decena. Seria imposible discriminar cual es cual, ya que la minima medida que abarca el  puntero son 8 bytes. ambos punteros tendrian la misma direccion de memoria 0x100 y 0x100


Muchas gracias Killer..me queda bien claro, ahora uno decide si ahorra memoria o ciclos de trabajo..

Muchas gracias y saludos..


Desconectado marvicdigital

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 311
Re:Como Leer punteros - Tutorial
« Respuesta #23 en: 18 de Agosto de 2018, 13:27:19 »
Hola a todos. Killer muchas gracias por tu tutorial, me ha servido mucho para la rutina que estoy haciendo...de hecho voy a compartir el código usado para un Atmega16, se que este no es el foro pero para ejemplo de uso de punteros viene bien..si hay algo que se pueda mejorar me pueden decir para aprender mas.:

Código: C
  1. /*
  2. Programa para controlar un display de ánodo comun
  3. con cuatro dígitos, usando registro por desplazamiento
  4. el IC CD4094 utilizando tres señales para controlarlo
  5. Dato // Clock // Output Enable que se encargará de
  6. encender los leds del display. Se USARA PUNTEROS
  7. Cada display estará conectado con un transistor PNP 2N3906
  8. para hacer la multiplexación de los cuatro display
  9. Todo se controlará por el puerto A
  10. Se manejará por interrupción del temporizador 0
  11.  
  12.  */
  13.  
  14. #define F_CPU 10000000UL
  15. #include <avr/io.h>
  16. #include <util/delay.h>
  17. #include <interrupt.h>
  18.  
  19.  
  20. #define PinDato  1            //definimos los pines para
  21. #define PinClk   2            //controlar el IC
  22. #define PinEnable 0           //CD4096 en el puerto A
  23. #define PuntoOn 0             //Muestra el display sin el punto
  24. #define PuntoOff 128          // muestra el display con el punto
  25.  
  26.  
  27.  
  28. //Definimos los valores para el display de ánodo común
  29.  
  30. unsigned char const Display[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
  31. unsigned char Punto=128;        //Variable para seleccionar si tendrá punto..por defecto no.
  32. unsigned char volatile Segundos=0;      //Se usa para multiplicar el tiempo de TMR0
  33. unsigned short volatile Cuenta=0;       //variable auxiliar para decidir si encender un display o no
  34. unsigned char volatile DisplayOn=0;     //Variable auxiliar para el tiempo de encendido de cada display
  35.  
  36.  
  37. //Estructura para ser controlada por el puntero *pUnidad
  38. ////////////////////////////////////////////////////////
  39.  
  40. struct {
  41.           unsigned char Unidad;
  42.           unsigned char Decena;
  43.           unsigned char Centena;
  44.           unsigned char Miles;
  45.  
  46. }Valor;
  47.  
  48. ////////////////////////////////////////////////////////
  49.  
  50.  
  51.  
  52.  
  53. // Rutina de envío de datos para el CD4094
  54. // SPI solo como master
  55.  
  56. void SpiEnviar(unsigned char Numero){
  57.  
  58.           PORTA &= ~(1<<PinEnable);     //Alta impedancia en las salidas del CD4094
  59.  
  60.           for(unsigned char i=0; i<8; i++){
  61.  
  62.                     if(((Display[Numero]+Punto)<<i)&0x80){
  63.  
  64.                               PORTA |=(1<<PinDato);
  65.                     }else{
  66.  
  67.                               PORTA &= ~(1<<PinDato);
  68.                     }
  69.                     _delay_us(5);                 //Tiempo de esperea para enviar datos
  70.                     PORTA |= (1<<PinClk);         // y el clk al CD4096
  71.                     _delay_us(5);
  72.                     PORTA &= ~(1<<PinClk);
  73.                     _delay_us(5);
  74.  
  75.          }
  76.           PORTA |= (1<<PinEnable);      //Muestra el dato
  77.  
  78.  
  79. }
  80.  
  81. void Timer0Ini(){
  82.  
  83.           TCCR0 = 0b00000100;
  84.           TIMSK|=(1<<OCIE0);
  85.           OCR0 = 38;
  86.           sei();
  87. }
  88.  
  89. ISR(TIMER0_COMP_vect){
  90.  
  91.           TCNT0=0;
  92.           DisplayOn++;        //Tiempo para encender el display
  93.           Segundos++;         //Usado para temporizador o contador de pulsos para pruebas
  94.  
  95. }
  96.  
  97. ///**************************************************//
  98.  
  99. void EscribirDisplay(unsigned char *pUnidad){
  100.  
  101.  
  102.           for(int i=6; i>2; i--){
  103.  
  104.  
  105.                     switch(i){                    //Rutina para encender o no el display
  106.                                                   //Dependiendo de decenas centenas o miles
  107.                               case 3:{
  108.                                         if(Cuenta>999){
  109.                                                   PORTA &= ~(1<<i);
  110.                                                   Punto=PuntoOn;
  111.  
  112.                                         }else{
  113.                                                   PORTA |= (1<<i);
  114.                                                   }
  115.                                         break;
  116.                               }
  117.                               case 4:{
  118.                                         if(Cuenta>99){
  119.                                                   PORTA &= ~(1<<i);
  120.                                         }else{PORTA |= (1<<i);}
  121.                                         break;
  122.                               }
  123.  
  124.                               case 5:{
  125.                                         if(Cuenta>9){
  126.                                                   PORTA &= ~(1<<i);
  127.                                         }else{PORTA |= (1<<i);}
  128.                                         break;
  129.                               }
  130.                               case 6:{
  131.                                        PORTA &= ~(1<<i);
  132.                                        break;
  133.                               }
  134.  
  135.  
  136.  
  137.                     }
  138.  
  139.                     SpiEnviar(*pUnidad);
  140.                     while(DisplayOn<5){};         //5ms para encender cada display
  141.                     PORTA |= (1<<i);
  142.                     PORTA &= ~(1<<PinEnable);     //Alta impedancia en las salidas del CD4094
  143.                     DisplayOn=0;                  //Reiniciamos los 5ms
  144.                     pUnidad++;                     //Aumentamos en 1 el puntero, siguiente dirección
  145.                     //Punto=PuntoOff;
  146.  
  147.  
  148.           }
  149.  
  150.  
  151.             if(Segundos >= 200){                  //Tiempo de conteo aprox 200ms
  152.  
  153.                     Cuenta++;
  154.                     if(Cuenta>=10000){
  155.                     Cuenta=0;
  156.  
  157.                     }
  158.                     Segundos=0;
  159.  
  160.           }
  161.           Punto=PuntoOff;
  162.  
  163. }
  164.  
  165.  
  166. int main(void)
  167. {
  168.  
  169.           DDRA = 0b01111111;
  170.           PORTA |= (1<<3)|(1<<4)|(1<<5)|(1<<6);   //Display apagados(lógica invertida)
  171.           PORTA &= ~(1<<PinClk); //CLK en cero
  172.           PORTA &= ~(1<<PinEnable);
  173.           Valor.Unidad=0;
  174.           Timer0Ini();
  175.  
  176.  
  177.     while(1){
  178.                     Valor.Unidad = Cuenta%10;               //Conversion para mostrar valor
  179.                     Valor.Decena =  (Cuenta%100)/10;        // en cada display
  180.                     Valor.Centena = (Cuenta%1000)/100;
  181.                     Valor.Miles = Cuenta/1000;
  182.  
  183.                     EscribirDisplay(&Valor.Unidad);
  184.  
  185.        }
  186.  
  187.     return 0;
  188. }

Se me olvidaba comentar que los display van conectados desde el puesto PTA3 hasta el PTA6, siendo este último el de las unidades y el PTA3 el de unidades de mil.


Saludos
« Última modificación: 18 de Agosto de 2018, 13:37:31 por marvicdigital »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #24 en: 18 de Agosto de 2018, 13:40:17 »
El problema es que si haces

                    EscribirDisplay(&Valor.Decena);

Seguramente veas lo mismo que tenes, por eso mismo te decia que no deberias usar el puntero al valor, sino la estructura completa.

Desconectado marvicdigital

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 311
Re:Como Leer punteros - Tutorial
« Respuesta #25 en: 18 de Agosto de 2018, 13:56:29 »
El problema es que si haces

                    EscribirDisplay(&Valor.Decena);

Seguramente veas lo mismo que tenes, por eso mismo te decia que no deberias usar el puntero al valor, sino la estructura completa.

Parece que no me ha quedado muy claro aún eso de los punteros a la estructuras  :(...osea que me sugieres que haga en ese mpunto? cuál sería la forma correcta y más eficiente?..gracias Killer por tu ayuda..aunque el código funciona muy bien si quiero tener muy claro este royo de puntero a estructura.

Saludos.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Como Leer punteros - Tutorial
« Respuesta #26 en: 18 de Agosto de 2018, 13:58:31 »
Perdon, crei que todavia estabas usando bitfields, al hacerlo con bytes completos si no hay problema. Me quede con la version antigua, perdon por generarte confusion.

Desconectado marvicdigital

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 311
Re:Como Leer punteros - Tutorial
« Respuesta #27 en: 18 de Agosto de 2018, 16:09:13 »
Perdon, crei que todavia estabas usando bitfields, al hacerlo con bytes completos si no hay problema. Me quede con la version antigua, perdon por generarte confusion.

 :mrgreen: ..ahh que susto me has pegado,, andaba ya perdido por el Himalaya  :D

Gracias y saludos.


 

anything