Reputation: 615
I have a problem in malloc/free
. I want to implement a simple 'ls' to show unhidden files in a dir.
Here is my code:
void do_ls(char *dirname, _Bool ls_list) {
DIR *dir_ptr;
const char * d_name;
struct dirent *direntp, ** dirarray;
int fcnt, d_name_max;
if((dir_ptr = opendir(dirname))==NULL) {
fprintf(stderr,"ls: cannot open %s\n", dirname);
exit(-1);
}
else {
fcnt = 0; // count unhidden files
d_name_max = -1; // max length of filename
while((direntp = readdir(dir_ptr))!=NULL) {
d_name = direntp->d_name;
if(d_name[0]!='.' ||\
strcmp(d_name, ".")==0 ||\
strcmp(d_name, "..")==0) {
fcnt++;
if((int)strlen(d_name)>d_name_max)
d_name_max = strlen(d_name);
}
}
// use a array to store dirent printer
dirarray = (struct dirent**)malloc(sizeof(struct dirent *)*fcnt);
// reset read position
seekdir(dir_ptr, 0);
int i = 0;
while((direntp=readdir(dir_ptr))!=NULL) {
if(d_name[0]!='.' ||\
strcmp(d_name, ".")==0 ||\
strcmp(d_name, "..")==0) {
dirarray[i++] = direntp; // save pointer
}
}
qsort(dirarray, fcnt, sizeof(struct dirent*), alphacmp); // qsort for lexicographical ordering
for(int i=0;i<fcnt;i++)
fprintf(stdout, "%s\n", dirarray[i]->d_name); // print result
if(dirarray!=NULL)
free(dirarray); // free if not NULL
closedir(dir_ptr);
}
}
It's confusing to me, thatit works or crashes in some cases. And I guess there must be some wrongs in do_ls
but still cannot find out.
Files under my dir are:
`ls -a ~/file/c/`
./ ../ 1* a.c db/ mpi/ test1.c .test1.c.swo .test1.c.swp unix/ .ycm_extra_conf.py .ycm_extra_conf.pyc
But when run ./my-own-ls ~/file/c/
, I'm getting these errors:
/home/panhzh3/file/c:
..
.test1.c.swo
.test1.c.swp
.ycm_extra_conf.py
.ycm_extra_conf.pyc
1
mpi
unix
*** glibc detected *** ./ls: free(): invalid next size (fast): 0x08d9b028 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75b12)[0xb7664b12]
./ls[0x80488e5]
./ls[0x8048a6f]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb76084d3]
./ls[0x8048621]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:0a 1183201 /home/panhzh3/file/c/unix/hw/ls
08049000-0804a000 r--p 00000000 08:0a 1183201 /home/panhzh3/file/c/unix/hw/ls
0804a000-0804b000 rw-p 00001000 08:0a 1183201 /home/panhzh3/file/c/unix/hw/ls
08d93000-08dbc000 rw-p 00000000 00:00 0 [heap]
b75b4000-b75d0000 r-xp 00000000 08:09 392702 /lib/i386-linux-gnu/libgcc_s.so.1
b75d0000-b75d1000 r--p 0001b000 08:09 392702 /lib/i386-linux-gnu/libgcc_s.so.1
b75d1000-b75d2000 rw-p 0001c000 08:09 392702 /lib/i386-linux-gnu/libgcc_s.so.1
b75ee000-b75ef000 rw-p 00000000 00:00 0
b75ef000-b7793000 r-xp 00000000 08:09 392617 /lib/i386-linux-gnu/libc-2.15.so
b7793000-b7795000 r--p 001a4000 08:09 392617 /lib/i386-linux-gnu/libc-2.15.so
b7795000-b7796000 rw-p 001a6000 08:09 392617 /lib/i386-linux-gnu/libc-2.15.so
b7796000-b7799000 rw-p 00000000 00:00 0
b77b3000-b77b7000 rw-p 00000000 00:00 0
b77b7000-b77b8000 r-xp 00000000 00:00 0 [vdso]
b77b8000-b77d8000 r-xp 00000000 08:09 392601 /lib/i386-linux-gnu/ld-2.15.so
b77d8000-b77d9000 r--p 0001f000 08:09 392601 /lib/i386-linux-gnu/ld-2.15.so
b77d9000-b77da000 rw-p 00020000 08:09 392601 /lib/i386-linux-gnu/ld-2.15.so
bff21000-bff43000 rw-p 00000000 00:00 0 [stack]
[2] 32254 abort (core dumped) ./ls ~/file/c
Source codes:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
int alphacmp(const void * a, const void * b) {
struct dirent ** ta = (struct dirent**)a;
struct dirent ** tb = (struct dirent**)b;
return strcmp((*ta)->d_name, (*tb)->d_name);
}
void do_ls(char *dirname, _Bool ls_list) {
DIR *dir_ptr;
const char * d_name;
struct dirent *direntp, ** dirarray;
int fcnt, d_name_max;
if((dir_ptr = opendir(dirname))==NULL) {
fprintf(stderr,"ls2: cannot open %s\n", dirname);
exit(-1);
}
else {
fcnt = 0;
d_name_max = -1;
while((direntp = readdir(dir_ptr))!=NULL) {
d_name = direntp->d_name;
if(d_name[0]!='.' ||\
strcmp(d_name, ".")==0 ||\
strcmp(d_name, "..")==0) {
fcnt++;
if((int)strlen(d_name)>d_name_max)
d_name_max = strlen(d_name);
}
}
dirarray = (struct dirent**)malloc(sizeof(struct dirent *)*fcnt);
seekdir(dir_ptr, 0);
int i = 0;
while((direntp=readdir(dir_ptr))!=NULL) {
if(d_name[0]!='.' ||\
strcmp(d_name, ".")==0 ||\
strcmp(d_name, "..")==0) {
dirarray[i++] = direntp;
}
}
qsort(dirarray, fcnt, sizeof(struct dirent*), alphacmp);
for(int i=0;i<fcnt;i++)
fprintf(stdout, "%s\n", dirarray[i]->d_name);
if(dirarray!=NULL)
free(dirarray);
closedir(dir_ptr);
}
}
int main(int argc, char **argv) {
const char * const short_options = "l";
const struct option long_options[] = {
{"list", 0, NULL, 'l'},
{NULL, 0, NULL, 0},
};
const char * program_name = argv[0];
opterr = 0;
int next_option;
_Bool ls_list = false;
do {
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
switch(next_option) {
case 'l':
ls_list = true;
break;
case '?':
fprintf(stderr, "Invalid option: -%c", optopt);
exit(-1);
break;
case ':':
fprintf(stderr, "Option -%c needs argument.", optopt);
case -1:
break;
default:
abort();
}
} while(next_option!=-1);
if(optind == argc)
do_ls(".", ls_list);
else
for(;optind<argc;optind++) {
printf("%s:\n", argv[optind]);
do_ls(argv[optind], ls_list);
}
return 0;
}
Upvotes: 2
Views: 1226
Reputation: 4767
In your second while loop, you are missing the line:
d_name = direntp->d_name;
One other thing you might need to know is that you can't depend on storing the dirent pointers in an array and sorting them. The man page for readdir
says that the data may be overwritten by subsequent calls, so you might have to make copies of each entry and sort the copies instead.
Upvotes: 1