C 我在递归函数中声明了一个数组。我该怎么分类呢?
我在递归函数中声明了一个数组。是否可以在输出前对其进行排序?我从另一个递归函数得到的大小C 我在递归函数中声明了一个数组。我该怎么分类呢?,c,recursion,directory,C,Recursion,Directory,我在递归函数中声明了一个数组。是否可以在输出前对其进行排序?我从另一个递归函数得到的大小 void listFilesRecursively(char *basePath, int size) { char path[1000]; struct dirent *dp; struct file files[size]; struct stat buf; DIR *dir = opendir(basePath); int counter = 0;
void listFilesRecursively(char *basePath, int size) {
char path[1000];
struct dirent *dp;
struct file files[size];
struct stat buf;
DIR *dir = opendir(basePath);
int counter = 0;
if (!dir) return;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp->d_name);
files[counter].name = path;
stat(path, &buf);
files[counter].file_info.st_size = buf.st_size;
printf("%s%s%ld%s\n", files[counter].name, " - ",
files[counter].file_info.st_size, "bytes");
counter++;
listFilesRecursively(path, size);
}
}
closedir(dir);
}
警告:
files[counter].name=path
保存一个局部变量地址,并且在每次循环中修改它,因此所有名称都相同,您需要保存它的副本(strdup)
对于ListFiles的每次递归调用,您在堆栈中使用的字节数超过1000个,最好不要在堆栈中使用该字符串,而是直接使用堆中分配的路径
我不认为有兴趣将文件和计数器作为局部变量,而是将它们释放出去
提议
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define NFILES 100;
typedef struct file {
char * name;
struct stat file_info;
} file;
void listFilesRecursively(char *basePath, file ** files, int * size, int * index)
{
DIR *dir = opendir(basePath);
if (!dir)
return;
struct dirent *dp;
struct stat buf;
while ((dp = readdir(dir)) != NULL)
{
if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
{
size_t sz = strlen(basePath);
char * pathname = malloc(sz + strlen(dp->d_name) + 2);
if (pathname == NULL) {
/* out of memory */
closedir(dir);
return;
}
strcpy(pathname, basePath);
pathname[sz] = '/';
strcpy(pathname + sz + 1, dp->d_name);
stat(pathname, &buf);
if (S_ISDIR(buf.st_mode)) {
/* suppose dirs not memorized */
listFilesRecursively(pathname, files, size, index);
free(pathname);
}
else if (S_ISREG(buf.st_mode)) {
/* a file, memorize it */
if (++*index == *size) {
*size += NFILES;
*files = realloc(*files, (*size) * sizeof(file));
}
(*files)[*index].file_info = buf;
(*files)[*index].name = pathname;
}
else
/* bypassed */
free(pathname);
}
}
closedir(dir);
}
int compPathname(const void * a, const void * b)
{
return strcmp(((file *) a)->name, ((file *) b)->name);
}
int main()
{
int size = NFILES;
int index = -1;
file * files = malloc(size * sizeof(file));
listFilesRecursively(".", &files, &size, &index);
if (index != -1) {
qsort(files, index + 1, sizeof(file), compPathname);
/* write and free memory */
for (int i = 0; i <= index; ++i) {
printf("%s : %ld\n", files[i].name, (long) files[i].file_info.st_size);
free(files[i].name);
}
}
free(files);
return 0;
}
您的方法不起作用:
- 在每个递归级别定义了一个新的数组
文件
- 为数组中的每个条目保存的路径相同,是指向函数中定义的本地数组
的指针path
文件
设置为全局变量,但应避免使用全局变量。相反,您应该将指针传递给递归函数外部定义的结构,并在递归下降过程中发现更多条目时在此结构内部重新分配数组。应使用strdup
分配每个文件的路径副本。为了限制堆栈空间要求,路径
也可以是此结构的一部分,并将目录部分的长度传递给递归函数
void listFilesRecursively(char *basePath, int size) {
char path[1000];
struct dirent *dp;
struct file files[size];
struct stat buf;
DIR *dir = opendir(basePath);
int counter = 0;
if (!dir) return;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp->d_name);
files[counter].name = path;
stat(path, &buf);
files[counter].file_info.st_size = buf.st_size;
printf("%s%s%ld%s\n", files[counter].name, " - ",
files[counter].file_info.st_size, "bytes");
counter++;
listFilesRecursively(path, size);
}
}
closedir(dir);
}
以下是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
struct file {
char *name;
struct {
long st_size;
} file_info;
};
typedef struct dir_state {
char path[1024];
struct file *files;
int files_size;
int files_count;
} dir_state;
int listFilesRecursively(dir_state *sp) {
struct dirent *dp;
struct stat buf;
int counter = 0;
int path_len = strlen(sp->path);
DIR *dir = opendir(sp->path);
if (!dir)
return 0;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
snprintf(sp->path + path_len, sizeof(sp->path) - path_len, "/%s", dp->d_name);
if (sp->files_count == sp->files_size) {
int new_size = sp->files_size * 3 / 2 + 16;
struct file *new_p = realloc(sp->files, new_size * sizeof(*new_p));
if (new_p == NULL)
return -1;
sp->files_size = new_size;
sp->files = new_p;
}
memset(&sp->files[sp->files_count], 0, sizeof(struct file));
sp->files[sp->files_count].name = strdup(sp->path);
if (!stat(sp->path, &buf))
sp->files[sp->files_count].file_info.st_size = buf.st_size;
printf("%s%s%ld%s\n", sp->files[sp->files_count].name, " - ",
sp->files[sp->files_count].file_info.st_size, "bytes");
sp->files_count++;
counter++;
listFilesRecursively(sp);
}
}
closedir(dir);
sp->path[path_len] = '\0';
return counter;
}
int cmp_name(const void *a, const void *b) {
const struct file *aa = a;
const struct file *bb = b;
return strcmp(aa->name, bb->name);
}
int cmp_size_name(const void *a, const void *b) {
const struct file *aa = a;
const struct file *bb = b;
if (aa->file_info.st_size < bb->file_info.st_size)
return -1;
if (aa->file_info.st_size > bb->file_info.st_size)
return +1;
return strcmp(aa->name, bb->name);
}
int main(int argc, char *argv[]) {
dir_state ds = { "", NULL, 0, 0 };
int i;
if (argc < 2) {
strcpy(ds.path, ".");
listFilesRecursively(&ds);
} else {
for (i = 1; i < argc; i++) {
strcpy(ds.path, argv[i]);
listFilesRecursively(&ds);
}
}
printf("\nFiles sorted by name:\n");
qsort(ds.files, ds.files_count, sizeof(*ds.files), cmp_name);
for (i = 0; i < ds.files_count; i++) {
printf("%10ld %s\n", ds.files[i].file_info.st_size, ds.files[i].name);
}
printf("\nFiles sorted by size and name:\n");
qsort(ds.files, ds.files_count, sizeof(*ds.files), cmp_size_name);
for (i = 0; i < ds.files_count; i++) {
printf("%10ld %s\n", ds.files[i].file_info.st_size, ds.files[i].name);
}
for (i = 0; i < ds.files_count; i++) {
free(ds.files[i].name);
}
free(ds.files);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
结构文件{
字符*名称;
结构{
长st_尺寸;
}档案信息;
};
类型定义结构目录状态{
字符路径[1024];
结构文件*文件;
int文件大小;
整数文件计数;
}迪鲁州;
int listfiles递归(dir_state*sp){
结构方向*dp;
结构统计buf;
int计数器=0;
int path_len=strlen(sp->path);
DIR*DIR=opendir(sp->path);
如果(!dir)
返回0;
而((dp=readdir(dir))!=NULL){
如果(strcmp(dp->d_name,“.”)=0和&strcmp(dp->d_name,“…”)!=0){
snprintf(sp->path+path\u len,sizeof(sp->path)-path\u len,“/%s”,dp->d\u name);
如果(sp->files\u count==sp->files\u size){
int new_size=sp->files_size*3/2+16;
结构文件*new\u p=realloc(sp->files,new\u size*sizeof(*new\u p));
if(new_p==NULL)
返回-1;
sp->文件大小=新大小;
sp->files=new\u p;
}
memset(&sp->files[sp->files_count],0,sizeof(struct file));
sp->files[sp->files\u count].name=strdup(sp->path);
如果(!stat(sp->path,&buf))
sp->files[sp->files\u count]。file\u info.st\u size=buf.st\u size;
printf(“%s%s%ld%s\n”,sp->files[sp->files\u count]。名称,“-”,
sp->files[sp->files\u count]。file\u info.st\u size,“字节”);
sp->files_count++;
计数器++;
递归列表文件(sp);
}
}
closedir(dir);
sp->path[path_len]='\0';
返回计数器;
}
int cmp_名称(常量无效*a,常量无效*b){
常量结构文件*aa=a;
常量结构文件*bb=b;
返回strcmp(aa->name,bb->name);
}
int cmp_大小_名称(常量无效*a,常量无效*b){
常量结构文件*aa=a;
常量结构文件*bb=b;
如果(aa->file\u info.st\u sizefile\u info.st\u size)
返回-1;
如果(aa->file\u info.st\u size>bb->file\u info.st\u size)
返回+1;
返回strcmp(aa->name,bb->name);
}
int main(int argc,char*argv[]){
目录状态ds={',NULL,0,0};
int i;
如果(argc<2){
strcpy(ds.path,“.”);
递归地列出文件(&ds);
}否则{
对于(i=1;i
注:
- 最大深度不受限制:由于此方法遵循符号链接,因此目录树中可能存在循环,导致相同路径被多次遍历。但是,由于
强制的路径长度限制,这不会导致无限递归snprintf
typedef结构文件{char*name;struct stat file_info;}文件代码>但是当我在函数外声明这个数组时,我得到了分段错误。。。因为我不仅需要列出数据,还需要对数据进行操作,比如排序、传输。。。谢谢你的回答@尼克:好的,我编辑了我的答案,一些小改动。必须在堆中分配警告文件,因为如果needed@Nick我不使用固定大小来保存路径名(例如,nochar name[256];
),这两种方法都是为了确保无论路径名的长度如何,都可以保存它,并且在路径名短于保留大小时,也不会白白消耗内存。对于文件也是一样的,我不使用固定大小的向量来管理任何数量的文件,也不使用大量的向量来消耗内存。Nfile不是1到不realloc每次到达一个文件我已经完成了这个项目,但我有最后一个问题。。。我是