翻博客的时候看到一个有意思的问题,所以就手动研究一下这个问题,
我觉得这个问题中描述的情况会导致内存泄漏(内存泄漏是什么)
(系统是Ubuntu 18.04的,可以直接去/usr/include找头文件中的定义)
1.
保险起见,我觉得应该去dirent.h看一看,毕竟函数是在这里定义的
嗯,opendir()会返回一个目录流
2.
再看看closedir()
3.
从函数声明以及头文件的注释这里并没有看到什么,
想起以前软工的学长给我推荐的一个检查内存泄露的分析工具Valgrind(Linux性能分析工具Valgrid),不妨拿出来玩一玩。
手头有一个现成的程序,我把其中的closedir()注释掉(line74),然后用valgrind检查.
#include <stdio.h> //perror()
#include <stdlib.h>
#include <string.h>
#include <errno.h> //strerror()
#include <sys/types.h> //opendir(),readdir() ,struct stat
#include <dirent.h> //opendir(), readdir()
#include <sys/stat.h> //struct stat , stat()
#include <unistd.h> //stat()
//如果DEBUG为true,则输出函数名称和行号,然后输出您想要打印的内容
//注意 这个报错宏并不会退出进程,你可以使用exit(-1) 来手动退出进程
int DEBUG=1;
#define DBGLOG(format, ...) if(DEBUG){ fprintf(stderr, "%s -- %d -- ", __FUNCTION__, __LINE__); fprintf(stderr, format, ##__VA_ARGS__);}
void do_ls(char* dirname); //访问各个目录
void do_stat(char* filename); //获取各个文件信息
void show_file_info(char * filename,struct stat *file_info);//展示单个文件的信息
int main(int argc,char **argv)
{
if(argc==1){
do_ls(".");
}else {
while(argc=argc-1){
printf("%s:\n",*++argv);
chdir(*argv); //切换工作目录到对应的路径 如果argv并非是目录文件,也可以这么做
do_ls(*argv);
chdir(""); //切换工作目录到当前目录 这一步是必要的吗
}
}
return 0;
}
void do_ls(char* dirname){//访问各个目录
DIR * dir_ptr;
struct dirent *dirent_ptr;
/********************************
struct dirent
{
long d_ino; //inode number 索引节点号
off_t d_off; //offset to this dirent 在目录文件中的偏移
unsigned short d_reclen; //length of this d_name 文件名长
unsigned char d_type; //the type of d_name 文件类型
char d_name [NAME_MAX+1]; //file name (null-terminated) 文件名,最长255字符
}
********************************/
if( (dir_ptr=opendir(dirname))==NULL ){
//如果不是目录文件,就会报错,并且直接进行do-stat()处理
DBGLOG("Cannot open %s , not a directory, treat as a file shown below:\n",dirname);
//这里并不退出进程 ,因为在ls命令中实参可以使用文件名
do_stat(dirname);
}else{ //是目录文件,需要用readdir()
while( (dirent_ptr=readdir(dir_ptr))!=NULL ){
do_stat(dirent_ptr->d_name);
}
}
// if( closedir(dir_ptr)==-1 ){ //关闭目录句柄失败
//DBGLOG("Closedir %s Error: %s\n",dirname,strerror(errno));
//
//exit(-1);
// }
}
void do_stat(char* filename){//获取各个文件信息
struct stat file_info;
/********************************
struct stat {
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
time_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //伟建内容对应的块数量
};
********************************/
if( stat(filename,&file_info)==-1 ){//读文件信息失败
DBGLOG("Get %s file_info error \n",filename);
exit(-1);
}else{//读文件信息成功
show_file_info(filename,&file_info);
}
}
void show_file_info(char * filename,struct stat *file_info){//展示单个文件的信息
printf("show_file_info: %s ;\n",filename);
}