2

我正在编写一个简单的程序来构建当前目录的目录索引。

每个文件都有两个用于文件名和最后修改时间的 char* 对象,以及一个用于文件大小的整数。

我想把所有这些放在一个大的stringorchar*中。

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>

using namespace std;

char* file_info(char*);
int main(void)
{
  DIR           *d;
  struct dirent *dir;
  d = opendir(".");
  if (d)
  {
    while ((dir = readdir(d)) != NULL)
    {
      file_info(dir->d_name);
    }

    closedir(d);
  }

  return(0);
}

char* file_info(char* file) {
    if(file[0] != '.') {
        struct stat sb;

        if (stat(file, &sb) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }

        char* lm = ctime(&sb.st_mtime);
        *lm = '\0';
        stringstream ss;
        ss << file << "           " << lm << "           " << sb.st_size;

        cout << ss.str() << endl;
    }
    return lm;
}

我希望返回char*的是一个具有这种格式内容的对象:

homework-1.pdf   12-Sep-2013  10:57   123K    
homework-2.pdf   03-Oct-2013  13:58   189K  
hw1_soln.pdf     24-Sep-2013  10:36   178K  
hw2_soln.pdf     14-Oct-2013  09:37   655K  

间距是这里的主要问题。我怎样才能轻松纠正它?到目前为止,我的尝试是

const char* file_info(char* file) {
    if(file[0] != '.') {
        struct stat sb;

        if (stat(file, &sb) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }

        char* lm = ctime(&sb.st_mtime);
        string lastmod(lm);
        lastmod.at(lastmod.size()-1) = '\0';
        stringstream ss;
        string spacing = "                                       ";
        ss << file << spacing.substr(0, spacing.size() - sizeof(file)) << lastmod << spacing.substr(0, spacing.size() - lastmod.size()) << sb.st_size;

        cout << ss.str() << endl;

        return ss.str().c_str();
    }
    else {
        return NULL;
    }
}

但它没有用,而且我使用的字符串非常糟糕。

4

5 回答 5

4

这是问题所在:

// ...
stringstream ss;
// ...
return ss.str().c_str(); // woops! ss goes out of scope and string will be destroyed!

这可以通过让你的函数返回std::string而不是char const*这样做来轻松解决:

return ss.str();

没有理由回到char const*这里。它使一切复杂化,需要手动内存管理,在某些时候会出现异常不安全,使调用您的函数的人感到困惑并使您的代码完全无法维护。

于 2013-11-05T07:17:49.000 回答
2

要回答您的 iostream 格式问题,您需要 std::setw

std::cout << "'" << std::setw(16) << "Hello" << "'" << std::endl;

http://faculty.cs.niu.edu/~mcmahon/CS241/c241man/node83.html

于 2013-11-05T07:31:27.383 回答
1

有两个不同的问题。首先,您显然不能const char *从堆栈分配的函数返回。所以你必须在堆上分配它。这就是问题所在。是所有权问题。你在哪里有delete这个字符串?使用 可以很容易地解决std::string

第二个问题是你的问题。如何使这很好地对齐。使用您的方法,您不能打印比预分配字符串更长的文件名。有一个简单的解决方案。在标头iomanip中定义了函数

/*unspecified*/ std::setw( int n );

上面写着“嘿,接下来要打印的内容必须是n字符长”。这就是你想要的。当您要打印的内容更长n时,它将全部打印出来。没有裁剪或类似的东西。

于 2013-11-05T07:33:23.250 回答
1

如果您绝对必须使用以空字符结尾的 C 字符串,而不是使用sprintf而不是 std::stringstream。像这样混合 C 和 C++ 被认为是不好的做法(就像已经指出的那样:即您必须手动管理内存)。您的代码还有其他一些问题:sizeof()运算符不计算字符串的长度 - 而是计算必要的内存空间(以字节为单位)。返回对ctime内部缓冲区的引用也不安全:

该函数还访问和修改共享的内部缓冲区,这可能会导致并发调用 asctime 或 ctime 时出现数据争用

而是使用 Call-by-reference 并且不返回任何内容。像这样:

void file_info(char* file, char* buffer) {
    if(file[0] != '.') {
        struct stat sb;
        if (stat(file, &sb) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }
        char* lm = ctime(&sb.st_mtime);
        *lm = '\0';
        sprintf(buffer, "%10s%10s%d", file, lm, sb.st_size);
    }
}

要解决您的格式问题,您还可以使用strlen()(但不是 sizeof())并根据 lm 和文件的长度使用空格。但是 sprintf 提供了一个固定长度的参数,带有 %"number of digits"s。

另请参阅:printf 参考

要打印的最小字符数。如果要打印的值比这个数字短,结果用空格填充。即使结果较大,该值也不会被截断。

但是你会在调用这个函数之前为 char* 缓冲区分配内存,并且必须确保它对于 sprintf 字符串(!)足够大。

IE

char buffer[256];
file_info(file, buffer);
printf("%s\n", buffer);
于 2013-11-05T07:35:36.540 回答
0

谢谢大家的答案。

但是,它们都没有按我的预期工作。(特别是,它不是用于输出,而是用于制作字符串对象。)

我最终实现了我想要的,但这绝不是好事。

不过,我在下面附上了我的程序。随意发表评论。

谢谢你。

void file_info(char*, stringstream&);

int main(void)
{
  DIR           *d;
  struct dirent *dir;
  d = opendir(".");
  stringstream ss;
  if (d)
  {
    while ((dir = readdir(d)) != NULL)
    {
      file_info(dir->d_name, ss);
    }

    closedir(d);
  }
  cout << ss.str() << endl;
  return(0);
}

void file_info(char* file, stringstream& ss) {
    if(file[0] != '.') {
        struct stat sb;

        if (stat(file, &sb) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }

        char* lm = ctime(&sb.st_mtime);
        string lastmod(lm);
        lastmod.at(lastmod.size()-1) = '\0';
        string spacing = "                                  ";
        ss << file << spacing.substr(0, spacing.size() - strlen(file)) << lastmod << spacing.substr(0, spacing.size() - lastmod.size()) << sb.st_size << '\n';

    }
    return;
}
于 2013-11-05T08:03:50.373 回答