Problema con índices

Iniciado por shulneos, 11 Agosto 2013, 22:49 PM

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

shulneos

Hola amigos, estoy teniendo un problema al definir una función, este es el codigo:
typedef struct {int *v; int n;}ArrayRep;
typedef ArrayRep *ArrayAp;

// Crea y devuelve un subarray del array a comprendido
// entre los índices i y j.
// Req: 1<=i<=j<=ArrayTam(a)
Array ArrayCreaSubarray(Array a, int i, int j)
{     
       ArrayAp ap=a;
       ArrayAp a2=ArrayCrea(j-i+1);
       for (int x=0; x<j-i+1;x++)   a2->v[x]=ap->v[i+x-1];
       return a2;
}

El problema es que no crea el subarray desde el índice i al indice j sino que genera un array con los primeros i-j+1 elementos.
Por ejemplo:
Si el array a fuese: 1 2 3 4 5 6.
Los enteros i y j fuesen: 2 y 4.
El array correcto sería:2 3 4 sin embargo se crea el 1 2 3.

Espero que alguien me pueda ayudar.

eferion

se te ha olvidado indicar la función problematica... ArrayCrea.

De todas formas, si necesitas crear un array con valores de X a Y, siendo ambos variables, necesitas pasar dos argumentos a la función:

* bien los valores de inicio y de fin
* bien el valor de inicio y la longitud de la secuencia.

Si solo pasas un valor como mucho podrás alcanzar a crear una secuencia de 0 a N o algo así.

la línea en cuestión debería quedar tal que:
Código (cpp) [Seleccionar]

ArrayAp a2=ArrayCrea(i, j);


No te puedo ayudar con la función porque, como te he comentado, se te ha olvidado ponerla.

shulneos

Lo siento, se me olvidó, aquí te la pongo.
// Crea y devuelve un array de tamaño n con sus elementos
// inicializados a cero e indexados desde 1 hasta n.
// Req: n>0
Array ArrayCrea(int n)
{
      ArrayAp a=malloc(sizeof(ArrayRep));
      a->n=n;
      a->v=malloc(sizeof(int)*n);
      for (int i=0;i<a->n;i++)
          a->v[i]=0;
      return a;     
}

Por eso solo tiene un argumento.

eferion

Vale, perdona cosas de lo tarde que es jejeje.

El problema lo tienes aqui:


for (int x=0; x<j-i+1;x++)   a2->v[x]=ap->v[i+x-1];


el código correcto debería ser:


for (int x=0; x<j-i+1;x++)   a2->v[x]=ap->v[i+x];


Si te das cuenta, x empieza en cero, luego el primer elemento a copiar i+x = 0+x = x.

Si le restas 1 y, por ejemplo, x fuese 0, entonces tendrías i+x-1 = 0+0-1 = -1 ... te saldrías del array.

shulneos

#4
No, eso no es, si te das cuenta el array a está indexado desde 1 hasta n, así que para el usuario sería el indice i y para el compilador seria i-1 ya que en C se empieza a indexar por el 0.

Yo tb llegué a liarme mucho con esto, la profesora nos amarga la vida  :-( :-(


De todos modos lo probé y sigue pasando lo mismo.

eferion

A ver, efectivamente, en programación los índices empiezan por cero... por tanto el primer elemento accesible de un vector es el 0.

Esto quiere decir que tu vector va a tener la siguientes valores en los siguientes índices:

Indice: 0  1  2  3  4  5 ...
Valor:  1  2  3  4  5  6 ...

Y, como tu comentas, tanto i como j son índices ( van de 0 a n ) ...

Si tu pones:

for (int x=0; x<j-i+1;x++)   a2->v[x]=ap->v[i+x-1];

para i=0, x=0 tienes aw->v[0]=ap->v[0+0-1]. Estás intentando acceder a la posición -1 de ap->v.

Ese -1 te sobra, en serio.

shulneos

A ver si puedo lograr que me entiendas. Cuando yo le estoy pidiendo al usuario que me indique dos valores, inferior y superior, el lo está haciendo en una escala de +1, para el usuario el primer índice es el 1, pero para el compilador el primer índice es el 0, como ya sabemos. Ahora si yo introduzco como parámetro en la función este índice, cuando vaya a dirigirme a él dentro de la función tendré que restarle 1 para que concuerden.

for (int x=0; x<j-i+1;x++)   a2->v
  • =ap->v[i+x-1];

    ejemplo:
    El usuario quiere que se cree un subarray b, a partir del array a, para ello introduce los índices 2 y 4 (para el compilador serían 1 y 3), estos son los argumentos i y j de la función.
    j-i+1=3
    a[0]=3; a[1]=6; a[2]=1; a[3]=9; a[4]=2; a[5]=0;
      Ahora el recorrido:
         
    x=0; a2->v[0]=a->v[2+0-1=1]; ------>a2->v[0]=6;
    x=1; a2->v[1]=a->v[2+1-1=2];------->a2->v[1]=1;
    x=2; a2->v[2]=a->v[2+2-1=3];------->02->v[2]=9;
    Fin de recorrido porque no se cumple la condición (x<3).

    Esta mañana he comprobado que el error raíz, está relacionado con otra función que carga el array desde un fichero. Ya que el resultado es correcto al crear el array desde la siguiente función que crea el array aleatoriamente.
    Array ArrayCreaAleatorio(int linf, int lsup)
    {
          ArrayAp a=malloc(sizeof(ArrayRep));
          a->n=lsup-linf+1;
          a->v=malloc(sizeof(int)*a->n);
          for (int i=0; i<a->n;i++)
              a->v[i]=linf+i;
          for (int j=0;j<=a->n-2;j++)
          {
              int k=EnteroAleatorio(j+1,a->n-1);
              int aux=a->v[j];
              a->v[j]=a->v[k];
              a->v[k]=aux;
          }
          return a;
    }


    Pero al crear el array desde un fichero si llamo a subarray con el array cargado en una variable, lo único que hace es imprimir los i-j+1 primer elementos.

    Aquí la función problemática:

    // Crea y devuelve un array cuyos elementos han sido
    // leídos desde un fichero de texto con descriptor de fichero f.
    // Req: El formato del fichero de lectura es el siguiente:
    //  n v_1 v_2 ... v_n
    //  con n>0.
    // Por ejemplo, el array {4,6,3,5} estaría en el fichero como:
    //  4 4 6 3 5
    Array ArrayCreaFichero(FILE * f)
    {
          ArrayAp a;
          fscanf(f,"%d",&a->n);
          a->v=malloc(sizeof(int)*a->n);
          for(int i=0;i<a->n;i++)
             fscanf(f,"%d",&a->v[i]);
          return a;
    }


    Y he comprobado que el error no se encuentra en el primer elemento del array(el que representa a n). Al imprimir por pantalla un array creado desde esta función devuelve lo esperado, en el caso del ejemplo: 4 6 3 5



eferion

Si no son índices no los llames como tales, nos ahorramos malentendidos :)

Cita de: shulneos en 11 Agosto 2013, 22:49 PM
El problema es que no crea el subarray desde el índice i al indice j sino que genera un array con los primeros i-j+1 elementos.

¿Puede ser que tu fallo esté relacionado con lo siguiente?


Array ArrayCreaAleatorio(int linf, int lsup)
{
      ArrayAp a=malloc(sizeof(ArrayRep));
      // ...
      return a;
}



Array ArrayCreaFichero(FILE * f)
{
      ArrayAp a;
      // ...
      return a;
}


Lo extraño es que no te salten errores de segmentación al usar memoria no inicializada.

shulneos

Te refieres a que debería haber inicializado también en la función de ArrayCreaFichero??

eferion

Cita de: shulneos en 16 Agosto 2013, 12:44 PM
Te refieres a que debería haber inicializado también en la función de ArrayCreaFichero??

Si ArrayAp es un puntero tienes que reservar memoria antes de utilizarlo.