[Curso] Introducción a la programación en C (XIV)

Moderadores: Kravenbcn, largeroliker, fidelcastro, cerealkiller, pspCaracas, m0skit0, LnD, ka69, zacky06

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

[Curso] Introducción a la programación en C (XIV)

Mensaje por m0skit0 »

<< Anterior Siguiente >>

"Microsoft no es la respuesta. Microsoft es la pregunta. NO es la respuesta" — Erik Naggum

Punteros (¡ay madre!)

Los punteros (todo el mundo tiembla de emoción y a la par cierto recelo) son la base de la potencia de C. Un puntero no es más que una dirección de memoria. Por tanto en arquitecturas de 32 bits, es un número de 32 bits. Este número indica (apunta) a una variable en memoria. Por ejemplo:

Código: Seleccionar todo

int* p;

Estoy diciendo que p es un puntero a un entero. Pero ojo, esto no quiere decir que estemos creando un entero. Sólo estamos creando el puntero (recordad esto bien, es un fallo muy común).

Los vectores/arrays también son punteros, pero con memoria reservada. Es decir, el "hueco" de las variables está reservado por la cantidad que pongamos. Por ejemplo:

Código: Seleccionar todo

char s[10];

es un puntero al primero de los 10 caracteres reservados. Esto es lo mismo que:

Código: Seleccionar todo

char* s = "123456789";

sólo que obviamente en ésta tenemos valores iniciales (también reservados en el caso de inicializar la variable). Esto es más claro si entendemos cómo funcionan las cadenas de caracteres en C.

Código: Seleccionar todo

s -> 1 2 3 4 5 6 7 8 9 \0

Esto nos dice que realmente s apunta al primer carácter, y todos los demás bytes (un char es un byte en C) forman una cadena hasta encontrar un carácter nulo (\0 código 0 en ASCII). Para ilustrar esto:

Código: Seleccionar todo

#include <stdio.h>

int main()
{
   char s[10] = "123456789";

   printf("La direccion de la cadena en memoria es 0x%X\n", s);
   printf("La cadena es %s\n", s);

   return 0;
}

Siendo s un puntero, podemos realizar operaciones matemáticas sobre él si lo casteamos como unsigned int (entero sin signo, lo que viene a ser un puntero :mrgreen: ).

Código: Seleccionar todo

#include <stdio.h>

int main()
{
   char s[10] = "123456789";

   int pos = 3;
   char* s0 = (char*)(unsigned int) s + pos; // s = s + pos
   printf("El carácter en posición %d es %c\n", pos, *s0);
   printf("La cadena es %s\n", s);

   return 0;
}

Veis que uso *s0 para indicar la variable a la que apunta el puntero (en este caso un char). El proceso inverso, es decir, obtener la dirección de una variable se hace con el operador &.

Código: Seleccionar todo

#include <stdio.h>

int main()
{
   int a = 10;
   int* p = &a;   
   printf("La dirección de memoria del entero a es 0x%X\n", p);
   printf("El valor de a es %d\n", *p);

   // Y sumamos 2
   a = *p + 2;
   printf("La dirección de memoria del entero a es 0x%X\n", &a);
   printf("El valor de a es %d\n", a);

   return 0;
}

Luego seguiré con más punteros, pero por ahora unos problemillas para relajarse la mente :mrgreen:

  • Imprimir cada carácter de una cadena de caracteres, recorriendo la cadena usando punteros y recursividad
  • Igual que el anterior pero imprimiendo la cadena al revés :katana:

¡Suerte y a darle al coco!

<< Anterior Siguiente >>
Imagen

arisma
Habitual
Habitual
Mensajes: 497
Registrado: 18 Sep 2009, 08:41

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por arisma »

Ejercicio 1
Spoiler:

Código: Seleccionar todo

#include <stdio.h>

void imprimeCaracterVector(char vector[], int pos)
{
   char *c;
   c = vector[pos];

   if ( c != '\0' )
   {
      printf("%c", c);
      imprimeCaracterVector(vector, ++pos);
   }
   else
   {
      printf("\n");
   }
}

void main(int args, char *argv[])
{
   char cadena[] = "Hola M0squit0!";

   imprimeCaracterVector(cadena, 0);
}


Ejercicio 2
Spoiler:

Código: Seleccionar todo

#include <stdio.h>

void imprimeCaracterVector(char vector[], int pos)
{
   char *c;
   if ( pos >= 0 )
   {
      c = vector[pos];
      printf("%c", c);
      imprimeCaracterVector(vector, --pos);
   }
   else
   {
      printf("\n");
   }
}

void main(int args, char *argv[])
{
   char cadena[] = "Hola M0squit0!";

   imprimeCaracterVector(cadena, sizeof(cadena));
}


P.D: Lo sé, lo sé. No debería haber saltado pero era muy tentador xD.

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por m0skit0 »

¡No problem! Y por fin alguien aparece por este hilo :lol:

No está mal, pero el segundo se puede hacer de una forma mucho más elegante, sin usar el sizeof() (de hecho sin necesidad de usar el tamaño de la cadena). Intenta encontrar cómo.
Imagen

Avatar de Usuario
brujitosexy
Experto
Experto
Mensajes: 1097
Registrado: 03 Sep 2009, 19:30

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por brujitosexy »

m0skit0 escribió:Y por fin alguien aparece por este hilo :lol:

Haces dias me preguntaba de la vida de el. :lol:

Me quede en el cap VIII, pero pronto regresare. :(
Linus Torvalds:
“El Software es como el sexo; es mejor cuando es gratis…”

Avatar de Usuario
~Rdavid~
Experto
Experto
Mensajes: 965
Registrado: 12 Nov 2009, 17:29
Ubicación: Costa Rica

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por ~Rdavid~ »

Lamento la tardanza xD

Primero
Spoiler:

Código: Seleccionar todo

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

void imprime_caracteres(int i, char *cadena)
{
      int distan;
      distan = strlen(cadena);
      
      if(i<distan)
      {
            printf("Caracter #%d: %c\n",i+1,*(cadena+i));
            i++;
            imprime_caracteres(i,cadena);
      }
      
}

int main(int argc, char argv[])
{
      char *cadena;
      int i=0;
      cadena = (char*)malloc(20*sizeof(char));
      printf("Escriba una cadena de caracteres: ");
      scanf("%s", cadena);
      
      
      imprime_caracteres(i,cadena);
      free(cadena);
      return 0;
}


Segundo
Spoiler:

Código: Seleccionar todo

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

void imprime_caracteres(int distan, char *cadena)
{
      
      if(0<=distan)
      {
            printf("Caracter: %c\n",*(cadena+distan));
            distan--;
            imprime_caracteres(distan,cadena);
      }
      
}

int main(int argc, char argv[])
{
      char *cadena;
      int distan;
      cadena = (char*)malloc(20*sizeof(char));
      printf("Escriba una cadena de caracteres: ");
      scanf("%s", cadena);
      
      distan = strlen(cadena)-1;      
      imprime_caracteres(distan,cadena);
      free(cadena);
      return 0;
}
Última edición por ~Rdavid~ el 08 Ene 2011, 00:43, editado 1 vez en total.
Imagen

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por m0skit0 »

Lo siento ~Rdavid~, pero el uso de malloc que haces es incorrecto. Estás reservando un único byte para toda la cadena (sizeof(char)) y eso es obviamente incorrecto.
Imagen

Avatar de Usuario
~Rdavid~
Experto
Experto
Mensajes: 965
Registrado: 12 Nov 2009, 17:29
Ubicación: Costa Rica

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por ~Rdavid~ »

m0skit0 escribió:Lo siento ~Rdavid~, pero el uso de malloc que haces es incorrecto. Estás reservando un único byte para toda la cadena (sizeof(char)) y eso es obviamente incorrecto.

Si, tienes razón, ya lo he editado agregando espacio suficiente es que creí que de esa manera se podía almacenar una cadena sin desperdiciar memoria y pues no me dio ningún error de compilación ni ejecución xD

¿Hay alguna manera de hacer eso sin desperdiciar memoria?
Imagen

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por m0skit0 »

~Rdavid~ escribió:creí que de esa manera se podía almacenar una cadena sin desperdiciar memoria

¿Por qué? Simplemente le estás diciendo que te reserve un byte de memoria. En C no hay ni trampa ni cartón. Lo único que se hace es lo que se dice.

~Rdavid~ escribió:no me dio ningún error de compilación ni ejecución

No te da errores de compilación porque no los hay. Lo que hay es error de lógica. Y no te dio errores al ejecutar porque fuiste muy buen chico probando. Prueba metiendo una cadena de 2000 caracteres, a ver qué pasa :lol:

~Rdavid~ escribió:¿Hay alguna manera de hacer eso sin desperdiciar memoria?

Una forma muy sencilla es reservar muchísima memoria y después reajustarla con realloc(). Hay maneras más sofisticadas, pero un poco más avanzadas que veremos más adelante.
Imagen

Avatar de Usuario
~Rdavid~
Experto
Experto
Mensajes: 965
Registrado: 12 Nov 2009, 17:29
Ubicación: Costa Rica

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por ~Rdavid~ »

Ah ok, mejor dejo de hacer cosas raras y me centro en lo que sepa :oki: ojala que lleguemos a esa parte :D
Imagen

Avatar de Usuario
CARDIHO
Enteradillo
Enteradillo
Mensajes: 67
Registrado: 02 Feb 2011, 17:15

Re: [Curso] Introducción a la programación en C (XIV)

Mensaje por CARDIHO »

Disculpen tengo una duda, ¿es bueno usar uniones en C y C++?.

Responder