我正在尝试K& R第8.6节中的列表目录示例,但在测试代码时,对目录中的每个文件都说“无法访问”。这是因为它是为Unix设计的?下面是我认为代码拼凑在一起时应该是什么样的,我错过了什么? ADD:如何修复此代码以使其正常工作?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "dirent.h"
#include <sys/dir.h>
#define NAME_MAX 14
typedef struct {
long ino;
char name[NAME_MAX+1];
} Dirent;
void fsize(char *);
/* print file sizes */
main(int argc, char **argv)
{
if (argc == 1)
fsize(".");
else
while (--argc > 0)
fsize(*++argv);
return 0;
}
void dirwalk(char *, void (*fcn)(char *));
/* fsize: print size of file "name" */
void fsize(char *name)
{
struct stat stbuf;
if (stat(name, &stbuf) == -1) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
dirwalk(name, fsize);
printf("%81d %s\n", stbuf.st_size, name);
}
#define MAX_PATH 1024
/* dirwalk: apply fn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
Dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
if (strcmp(dp->name, ".") == 0
|| strcmp(dp->name, "..") == 0)
continue;
if (strlen(dir)+strlen(dp->name)+2 > sizeof(name))
fprintf(stderr, "dirwalk: name %s/%s too long\n",
dir, dp->name);
else {
sprintf(name, "%s/%s", dir, dp->name);
(*fcn)(name);
}
}
closedir(dfd);
}
答案 0 :(得分:7)
从哪里开始....
struct dirent
。此外,将来知道:
会很有帮助如上所述,可以更轻松地解决您的问题。但更重要的是,你提到你正在学习“K&amp; R C”。注意,“K&amp; R C”早于国际标准组织(ISO)对C编程语言的标准化。自K&amp; R C以来,已经进行了几次ISO C:ISO C 1989(a.k.a.C89),ISO C 1990(a.k.a.C90)和ISO C 1999(a.k.a.C99)的迭代。我强烈建议你从一本更新的书中自学。
另外,如果您的目标是UNIX,我强烈建议您熟悉UNIX手册页。 UNIX Manual Pages chrome extension可让您轻松访问official IEEE Std. 1003.1 POSIX manual pages。我强烈建议您查看这些内容,以了解可用的标准功能,输入的预期内容,输出的保证以及它们可能会如何失败。
答案 1 :(得分:5)
您的示例中定义的结构Dirent
可能与您的系统struct dirent
不匹配(它不在我的系统中)。
在Linux系统上,以下内容将解决问题:
/* dirwalk: apply fn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
struct dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
if (strcmp(dp->d_name, ".") == 0
|| strcmp(dp->d_name, "..") == 0)
continue;
if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))
fprintf(stderr, "dirwalk: name %s/%s too long\n",
dir, dp->d_name);
else {
sprintf(name, "%s/%s", dir, dp->d_name);
(*fcn)(name);
}
}
closedir(dfd);
}
readdir
功能是系统特定的,因此您应该查阅您的文档。在Linux系统上,您可以在终端中键入man 2 readdir
以查看readdir
功能的在线手册。
答案 2 :(得分:2)
您的具体问题是您的自制Dirent
。 readdir
实际上会返回struct dirent *
,其布局不一定与您的Dirent
匹配,特别是在d_name
之前可能会有更多成员。所以,当你看到你的dp->name
得到这个名字时,你可能最终会尝试将一些非字符串作为一个字符串读出来,这会让你胡说八道;一旦你胡说八道,一切都会崩溃。
因此,修复Michael Aaron Safyan提到的所有内容,打开编译器的警告标志(-Wall -Werror
是gcc的良好起点),并且您的程序应该开始工作。
答案 3 :(得分:2)
当您查看编译器警告时,问题很明显。至少在我的系统上,GCC给出了:
x.c: In function ‘dirwalk’:
x.c:58:16: warning: assignment from incompatible pointer type
这是while ((dp = readdir(dfd)) != NULL) {
行。正如迈克尔指出的那样,struct dirent
已经存在,这就是readdir
返回的内容。您正在使用自定义的,不兼容的结构,这会导致您获取垃圾而不是文件/目录名称。
使其工作的最快捷方法是摆脱Dirent
并改为使用struct dirent
。