Arrays bidimensionales + funciones ¿? [C]

Bueno, a ver como explico esto.

Es continuación de directorios, entonces a ver.

Una vez abro el directorio, paso un while donde voy guardando los nombres en un array bidimensional:

while((infodir = readdir(directorio)) != NULL )
     {                               
                                      for(int g = 0; g < (int)strlen(infodir->d_name); g++){
                                              sprintf(&buffer[g][rom], "%c", infodir->d_name[g]);
                                              }
                                      rom++;
                   }


Y bueno, una vez los tengo almacenados en una variable declarada dentro de la funcion, como hago el return? o como me aconsejais hacer algo de este tipo?

saludo y grax.
¿Como declaras el array? Me supongo que con malloc ¿no? Si es asi puedes que como lo estas haciendo tengas una fuga de memoria (puede no, seguro [+risas])

Intenta algo así:

int i = 0;
int count = countFilesOfDir(path);   // Tu funcion donde cuentas el numero de ficheros en un directorio.

// Reservamos memoria para los nombres.
char **names = malloc(count * sizeof(char*));
for (i = 0; i < count; i++)
   names[i] = malloc(255 * sizeof(char));

getFileNamesOfDir(path, names);   // Tu funcion donde obtienes los nombres de los ficheros. Es donde debes meter el bucles while que has posteado
                                  // La funcion los guarda en array "names" y ya no necesita devolver nada.

.... // Haz lo que tengas que hacer con los nombres.

free(names); // Libera la memoria.


Y bueno, ¿tienes algún impedimento técnico para no usar String.h? Es que veo que estás copiando las cadenas a pelo y me estraña XD

Si tienes la posibilidad de usar dicha biblioteca es mejor hacer algo así:

int i = 0;
int len = 0;

while((infodir = readdir(directorio)) != NULL )
{       
   len = strlen(infodir->d_name);
   strncpy(&buffer[i++], infodir->d_name, len);                       
}



Un saludo [bye] [bye]
Podrías explicar un poco el code? ^^''

Impedimentos ninguno, lo que pasa que strcpy me lo copiaba todo y strncpy no lo conocia XD

Muchisimas gracias!

PD: es recomendable que cuando declaras el array reserves memoria? siempre?
nazareth escribió:PD: es recomendable que cuando declaras el array reserves memoria? siempre?


No es que sea recomendable, es que siempre que declaras una variable (del tipo que sea) es el modo de "reservar" memoria. Lo que pasa que hay dos modos de reservar memoria: estáticamente o dinámicamente.

Por ejemplo, en este caso, si supieses que siempre va a haber, por ejemplo, 100 ficheros en todos los directorios, pues podrías declarar el array estáticamente, tal que así:

char nombres[100][255];


Lo anterior indica que el array va a tener 100 nombres, y cada nombre a su vez tiene 254 caracteres como máximo (no se si lo sabrás, pero las cadenas deben terminar siempre en '\0', de ahí que aunque reserve para 255 caracteres en verdad el nombre solo podrá tener 254, si reservamos 50, solo podremos guardar 49, y así siempre).

En cambio, seguramente los usuarios de tu app no te hagan caso y quieran tener los ficheros que les de la gana en un directorio XD, así que no te queda otra que reservar memoria dinámicamente, tal y como te puse antes:

char **nombres = malloc(numero_de_ficheros * sizeof(char*));
for (i = 0; i < numero_de_ficheros; i++)
   nombres[i] = malloc(255 * sizeof(char));


En la primera línea estamos asignando memoria para que quepan en el array tantos nombres como valor tenga "numero_de_ficheros" almacenado. Si vale 100, cabran 100 o menos; si vale 50, cabran 50 o menos; etc.

Luego, debemos asignar a cada string, una por una, su capacidad. Ahí entra en juego el "for".

Como ves, asignar la memoria dinámicamente te da más control, pero como contrapartida eres tu el responsable de liberar esa memoria (si lo haces estáticamente, se gestiona "sola"). De ahí que luego de usar una variable declarada con "malloc" debas liberarla con "free".

Y creo eso es todo lo que te puedo decir, espero que me haya explicado medianamete bien [+risas]


nazareth escribió:Podrías explicar un poco el code? ^^''


Creo que lo que te puede chocar más es ¿por que no declarar el array en la función "getFileNamesOfDir" y devolverlo? Simple, por que es uno de los principios básicos de gestión de memoria. Si una función reserva memoria dentro de ella, es su responsabilidad liberar esa memoria antes de retornar (esto es un "convenio", no es una obligación, por ejemplo hay casos en los que es necesario reservar memoria en una función y no librarla en la misma, pero suele ser cuando estes implementando algún tipo de estructura de datos. Sin ir más lejos, puede que "opendir" haga algún "malloc" y que el "closedir" haga sus correspondientes "free").

Y en este caso eso no sería posible. De ahí que primero inicializo el array y luego le paso el bufer a la función para que me lo llene. Una vez llenado el array, lo uso y cuando termine con el lo libero.

Y eso es todo, si ves que no entiendes algo más o quieres que profundice en algo, dímelo e intentaré escribirte otro tochaco XD

Un saludo [bye] [bye]
Una cosilla mas, la funcion "getFileNamesOfDir(path, names);" no retorna el array no? Al ser externo las modificaciones que apliques quedan hechas, correcto?
Asi es, al pasarle un puntero como parámetro, todas la modificaciones que le hagas quedaran almacenadas. De todas formas podrías devolver dicha variable si quisieses, para hacer por ejemplo "ejecuciones en cadena". Es una prática muy común. Sin ir más lejos la mayoría de las funciones que estás usando de String.h también devuelven el buffer que les pases (por ejemplo strcpy/strncpy devuelve el buffer que les pasas como primer parámetro).

Dependiendo de si quieres o no devolver algo, la cabecera sería algo así:

void getFileNamesOfDir(char *path, char **names);


o

char **getFileNamesOfDir(char *path, char **names);


Y a la hora de usar el parámetro names ya no es necesario el '&' (en el anterior ejemplo se me coló [mad]). Una implementación sencilla sin ningún tipo de chequeo de errores:

DIR *directorio = opendir(path);
struct dirent *infodir = NULL;
int i = 0;

while((infodir = readdir(directorio)) != NULL)
   strncpy(names[i++], infodir->d_name, 254);                       

closedir(directorio);

return names; // dependiendo de si quieres o no devolver la referencia.


Saludos [bye] [bye]
Tengo que probar con esto último, ya que si hay varios archivos en carpeta, tiene que tocarlos todos, entonces sería hacer como bucle tantas veces como archivos haya.

Thx, voy a ponerme a ello.

PD: al declarar los arrays de esa forma

// Reservamos memoria para los nombres.
char **names = malloc(count * sizeof(char*));
for (i = 0; i < count; i++)
   names[i] = malloc(255 * sizeof(char));


Me tira un error:

error: invalid conversion from 'void*' to 'char**' [-fpermissive]
Prueba a poner un casting:

char **names = (char**)malloc(count * sizeof(char*));


names[i] = (char*)malloc(255 * sizeof(char));
Si, con casting compila, sigo con ello.

Gracias.

PD: una pregunta, si el array es bidimensional, cada vez que haces strncpy, salta a otro o lo copia en el mismo? es decir:

Si tenemos:

char **array;


Y hacemos un:

strncpy(array[i++], aux, len);


Si vuelves a usar strncpy(), te pasa a otra fila o sigue siempre en la misma? No se si me explico bien ^^''
Fijate en el "i++" de la línea que has puesto:

strncpy(array[i++], aux, len);


Es ahí donde controla la posición. Dicha línea es quivalente a estas dos:

strncpy(array[i], aux, len);
i++;
Vale, todo terminado, funciona como quiero, muchisimas gracias ^^

Pero la cosa no acaba aquí, si tengo dudas pondré otro hilo :p
10 respuestas