Control de usuario
Patrocinadores
Estadísticas
Miembros:
334.510
Online:
1.534
Hilos:
1.380.379
Mensajes:
24.870.692
Stats

Índice de foros Otras Consolas Desarrollo

Arrays bidimensionales + funciones ¿? [C]

Dedicado al desarrollo de software casero para videoconsolas

Moderador: jiXo

nazareth
Avatar de usuario
I'm Finishing
 
Mensajes: 2466
Registrado: 03 Ene 2008
Ubicación: Cartagena

Arrays bidimensionales + funciones ¿? [C]

Mensajepor nazareth 08 Jul 2011 15:16

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:

Código: Seleccionar todo
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.

rYlEi
Avatar de usuario
MegaAdicto!!!
 
Mensajes: 1180
Registrado: 16 Jul 2003
Ubicación: A Coruña

Mensajepor rYlEi 08 Jul 2011 16:35

¿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í:

Código: Seleccionar todo
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í:

Código: Seleccionar todo
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]

nazareth
Avatar de usuario
I'm Finishing
 
Mensajes: 2466
Registrado: 03 Ene 2008
Ubicación: Cartagena

Mensajepor nazareth 08 Jul 2011 18:10

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?

rYlEi
Avatar de usuario
MegaAdicto!!!
 
Mensajes: 1180
Registrado: 16 Jul 2003
Ubicación: A Coruña

Mensajepor rYlEi 08 Jul 2011 18:55

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í:

Código: Seleccionar todo
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:

Código: Seleccionar todo
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]

nazareth
Avatar de usuario
I'm Finishing
 
Mensajes: 2466
Registrado: 03 Ene 2008
Ubicación: Cartagena

Mensajepor nazareth 09 Jul 2011 10:44

Una cosilla mas, la funcion "getFileNamesOfDir(path, names);" no retorna el array no? Al ser externo las modificaciones que apliques quedan hechas, correcto?

rYlEi
Avatar de usuario
MegaAdicto!!!
 
Mensajes: 1180
Registrado: 16 Jul 2003
Ubicación: A Coruña

Mensajepor rYlEi 09 Jul 2011 11:06

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í:

Código: Seleccionar todo
void getFileNamesOfDir(char *path, char **names);


o

Código: Seleccionar todo
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:

Código: Seleccionar todo
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]

nazareth
Avatar de usuario
I'm Finishing
 
Mensajes: 2466
Registrado: 03 Ene 2008
Ubicación: Cartagena

Mensajepor nazareth 09 Jul 2011 11:12

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

Código: Seleccionar todo
// 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:

Código: Seleccionar todo
error: invalid conversion from 'void*' to 'char**' [-fpermissive]

rYlEi
Avatar de usuario
MegaAdicto!!!
 
Mensajes: 1180
Registrado: 16 Jul 2003
Ubicación: A Coruña

Mensajepor rYlEi 10 Jul 2011 11:54

Prueba a poner un casting:

Código: Seleccionar todo
char **names = (char**)malloc(count * sizeof(char*));


Código: Seleccionar todo
names[i] = (char*)malloc(255 * sizeof(char));

nazareth
Avatar de usuario
I'm Finishing
 
Mensajes: 2466
Registrado: 03 Ene 2008
Ubicación: Cartagena

Mensajepor nazareth 10 Jul 2011 15:30

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:

Código: Seleccionar todo
char **array;


Y hacemos un:

Código: Seleccionar todo
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 ^^''

rYlEi
Avatar de usuario
MegaAdicto!!!
 
Mensajes: 1180
Registrado: 16 Jul 2003
Ubicación: A Coruña

Mensajepor rYlEi 10 Jul 2011 21:09

Fijate en el "i++" de la línea que has puesto:

Código: Seleccionar todo
strncpy(array[i++], aux, len);


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

Código: Seleccionar todo
strncpy(array[i], aux, len);
i++;

Siguiente

Volver a Desarrollo

¿Quién está conectado?

Usuarios navegando por este foro: No hay usuarios registrados visitando el foro y 2 invitados