[C con Clase] Problema con puntero a puntero char

Steven Richard Davidson stevenrichard.davidson en gmail.com
Jue Oct 18 21:59:35 CEST 2007


Hola Ariel,

On 10/18/07, Ariel Romero <aromero en cenatav.co.cu> wrote:
> Hola a todos:
>
> Soy nuevo en C y quiero hacer una funcion que abra un directorio
> determinado y devuelva la lista de ficheros de primer nivel que existen
> en él. Esto fue lo que hice:
>

Veamos el código fuente.

>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/types.h>
> #include <dirent.h>
> #include <errno.h>
>
>     char** listFilesFromDirectory(char* directory){
>         DIR *dip;
>         struct dirent   *dit;
>         int             i = 0;
>         char** filesListFromDirectory;
>
>         if ((dip = opendir(directory)) == NULL){
>             perror("opendir");
>             return NULL;
>             }
>
>         printf("Directory stream is now open\n");
>
>         filesListFromDirectory = malloc(1);

Esto va a provocar problemas. Aquí estás adjudicando memoria para 1
solo byte. Esto no será suficiente para guardar una cadena de tipo
'char *'. Observa que se trata de un puntero que por lo general hoy en
día ocupa 4 bytes, bajo una plataforma de 32 bits.

Lo que debes hacer es crear memoria para una lista de cadenas. Según
he mirado, no hay forma de determinar la cantidad de ficheros que hay
en un directorio usando estas funciones que manejan sistemas de
ficheros independientes. Por lo tanto, tienes dos opciones:
1. Crea un array - estático o dinámico - con cantidades establecidas
de cadenas de caracteres.
2. Implementa una lista dinámicamente enlazada para ir agregando
nombres de cada fichero encontrado.

>         while ((dit = readdir(dip)) != NULL){
>             filesListFromDirectory[i]= malloc(sizeof(dit->d_name));

Esto no funcionará correctamente. El campo 'd_name' es un array de
'char' con una cantidad indeterminada de caracteres. El operador
'sizeof' seguramente se evaulará a 1 byte. Nuevamente, tienes dos
opciones:
1. Usa 'strlen()' para determinar la cantidad exacta de caracteres
para cada nombre.
2. Usa el campo 'd_reclen' de la estructura 'dirent'. Creo, pero no
estoy seguro, que este campo no siempre existe bajo todas las
implementaciones de esta biblioteca. Por lo tanto, es posible que no
puedas usar esta opción.

Ten presente que la cantidad de caracteres para 'd_name' no superará
el valor de la constante 'NAME_MAX'.

>             strcpy(filesListFromDirectory[i],dit->d_name);
>             i++;
>             }
>         filesListFromDirectory[i]= malloc(1);

Esto no funcionará correctamente, ya que estás creando memoria para 1
byte, pero posteriormente copias 4.

>         filesListFromDirectory[i]="end";

Esto puede o no funcionar como esperas. La existencia y duración de
"vida" de las cadenas literales se basa en la implementación del
compilador. Si el compilador decide eliminar esta cadena
temporalmente, entonces es posible que tengas problemas con tu lista
de nombres de ficheros. Sugiero crear memoria para esta cadena y
copiarla. Esto sería,

filesListFromDirectory[i] = (char *) malloc(4);
strcpy( filesListFromDirectory[i], "end" );

>         int var;

No usas esta variable, por lo que puedes eliminarla.

>
>         if (closedir(dip) == -1){
>             perror("closedir");
>             return 0;
>             }
>         return filesListFromDirectory;
>     }
>
> despues en el main para probar y listar los ficheros hago esto:
>
> int main(int argc, char **argv) {
>     char** list; //= malloc(1);
>     list = listFilesFromDirectory("res");
>     int var = 0;
>     while (list[var]!=NULL) {
>         puts(list[var]);
>         var++;
>     }

Antes de terminar el programa, debes liberar la memoria que
previamente creaste. En tu caso, debes ir liberando la memoria de cada
cadena de caracteres de 'list' y luego liberar la memoria de 'list',
en sí.

>     return EXIT_SUCCESS;
> }
>
> Pero no sé que sucede que me da error, alguien sabe como hacerlo bien,
> espero que me pueda ayudar.


Espero que todo esto te sirva.

Steven




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