[C con Clase] Array de cadenas de caracteres y paso de parámetros en C.

Rolando Kindelan Nuñez rkindelan en uci.cu
Mie Dic 10 21:04:22 CET 2008


EL problema es que lo que estas haciendo en 


  .....
  char (*string_pointers)[11];
 .....

No es un arreglo de caracteres normal, mas bien es un puntero a un arreglo de 11 caracteres, por lo tanto cualquier intento de variar esto te acarrea un error de asignacion de tipos incompatibles.
Ej
Para char (*string_pointers)[11]; lo que se le asigna es la direccion de memoria de un arreglo de 11 char, algo como lo sgte
char cadena[11];
string_pointers = &cadena;

cualquier intento de modificacion trae un error consigo por ejemplo si el tipo de 'cadena' no es char sino int, o si la cantidad de elementos no es 11 sino 10. Ahora bien qué puede pasar, como el tipo char [] no es un arreglo tradicional del lenguaje y es tratado con algunas especificidades puede que en algunas ocasiones funcione.

Tampoco podrias incrementar el puntero string_pointer asi sin mas (corres el riesgo de borrar lo que sea que este en la memoria), en vez de eso deberias tratar los punteros como una lista enlazada o crear un arreglo dinamico de punteros a punteros a arreglos char [11]

Para que todo te sea mas sencillo puedes renombrar el tipo char(*)[11] a PCHAR11

typedef char (*PCHAR11)[11];  // ahora PCHAR11 es un nuevo ID para el puntero a arreglo de 11 caracteres

struct string_list
{
  PCHAR11* string_pointers; // aqui tienes un arreglo de PCHAR11
  unsigned int number_of_strings;
};

void muestra_cadena(char* cad)
{
  printf("%s\n", cad);
}

PCHAR11* add_cadena(char* otro_char11, PCHAR11* stringList, int cap)
{
   PCHAR11* Temp = (PCHAR11*)malloc((cap + 1) * sizeof(PCHAR11));
   unsigned int i;
   for(i = 0; i < cap; i++)
     Temp[i] = stringList[i];

  if(strlen(otro_char11) > 11)
  {
    free(Temp);
    return stringList;
  }

  if(stringList)
   free(stringList);
 /*
 en la linea de abajo desreferencio el puntero al arreglo para
 tener acceso al arreglo y entonces le copio lo que quiero
 */
 strcpy( *(Temp[cap]), otro_char11);

 return Temp;
}

void get_file_names(const char *directory, struct string_list *file_names)
{
   struct dirent *d;
   struct stat buf;
   DIR *dir;
   PCHAR11* aux;
   file_names->number_of_strings = 0;
   file_names->string_pointers = 0;

   if ((dir=opendir(directory)) == NULL)
   {
      /* error */
   }

   while ((d=readdir(dir)) != NULL)
   {
      /* The above line avoid infinite loop */
      if (strcmp(d->d_name,".")!=0 && strcmp(d-> d_name, "..")!=0)
      {
        aux = add_cadena (d->d_name, file_names->string_pointers, file_names->number_of_strings);  // suponiendo que d->d_name es de tipo char* con 11 caracteres;
        if(aux != file_names->string_pointers)
         {
           file_names->string_pointers = aux;
           file_names->number_of_strings++;
         }
      }

   }

   closedir(dir);

}


Debes hacer algo como eso, espero te sirva.


Ing. Rolando Kindelan Nuñez
Universidad de las Ciencias Informáticas
-------------------------------------------------------------------
"Pensar en el futuro, hace el presente más complicado."  (by rolo...)




-----Original Message-----
From: cconclase-bounces en listas.conclase.net [mailto:cconclase-bounces en listas.conclase.net] On Behalf Of gmh2000
Sent: Wednesday, December 10, 2008 7:41 AM
To: cconclase en listas.conclase.net
Subject: Re: [C con Clase] Array de cadenas de caracteres y paso de parámetros en C.

Gracias a todos. Me he comido bien el coco pero parece que cada vez la solución va a peor. 

Da un warning y desde luego no funciona:
file_names->string_pointers = &d-> d_name;

No da errores pero la salida son cientos de caracteres sin sentido:
file_names->string_pointers = (char (*)[11]) d-> d_name;

Sin errores de compilación pero el programa casca y se cierra solo:
strncpy(file_names->string_pointers[file_names->number_of_strings++], d-> d_name, 11 );

Todas estas soluciones son SIN usar malloc(). Lo he intentado con esta función pero me da el error de siempre sobre los tipos en las asignaciones (en el código  he puesto mi intento más lógico).

Por otra parte no entiendo para que hay que reservar memoria con malloc() y/o cuando y porqué hay que liberarla con free().

Recuerdo que la versión en la que asignaba memoria de la forma "facil" con un array medio-funcionaba. Me explico: cuando pedía que me mostrara las cadenas algunas veces mostraba lo deseado, y otras veces algunas cadenas correctamente y otras en chino. Haber si esto ayuda algo para que me ayudeis. ¿Esto puede ser debido a que la cadenas las copiaba por referencia y no por valor?

Otra pregunta: ¿al hacer la copia por referencia el recolector de basura no elimina el resto de la estructura donde está contenido d->d_name?

Haber si me podeis echar el vigésimo-noveno cable. Quizás sea mejor partir de la solución que medio funcionaba, pero supongo que sería muy bueno quedarme con todos estos conceptos claros para un futuro, en cualquier caso...

Otra duda conceptual es que cuando pongo a las cadenas una longitud de 11, como se ve en el código, es porque la inmensa mayoría tienen 10 caracteres. Reservo 11 porque creo recordar que el último caracter es el /0. ¿Esto lo hago bien? ¿Puede ser el causante de los problemas esto?

Ahí va el resumen del código, con el intento de malloc:




struct strings_list
{
  char (*string_pointers)[11];
  unsigned int number_of_strings;
};

struct strings_list file_names;

get_file_names("/usr/lib/locale/", &file_names);

/* Acceso a las cadenas */
for (i = 0, i < file_names.number_of_strings; i++)
{
  muestra_cadena(file_names.string_pointers[i])
}





void get_file_names(const char *directory, struct strings_list *file_names)
{
   struct dirent *d;
   struct stat buf;
   DIR *dir;   
   file_names-> number_of_strings = 0;
   if ((dir=opendir(directory)) == NULL)
   {
      /* error */
   }   

   while ((d=readdir(dir)) != NULL)
   {   
      /* The above line avoid infinite loop */
      if (strcmp(d->d_name,".")!=0 && strcmp(d-> d_name, "..")!=0)
      {
      /* la línea de abajo da mi error preferido: incompatible types in assignment */
      file_names->string_pointers[file_names->number_of_strings] = (char *) malloc(11* sizeof(char));	
		strncpy(file_names->string_pointers[file_names->number_of_strings++], d-> d_name, 11 );

      }

   }

   closedir(dir);   

} 
_______________________________________________
Lista de correo Cconclase Cconclase en listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ


Más información sobre la lista de distribución Cconclase