2013-11-05 74 views
2

我正在写一个简单的程序,用于构建当前目录的目录索引。如何把不同的C字符串放在一个漂亮的格式?

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

我想把所有这些放在一个大的stringchar*

#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; 
    } 
} 

,但它没有工作,我用绳子工作如此糟糕。

+0

不要返回'char const *'为了爱的右边缘。返回'std :: string'。 – rightfold

+0

这是C++,而不是C.你应该改变标题来反映这一点。 –

+1

而不是尝试和每个迭代组成一个完整的字符串,与每个字段(名称,日期/时间,大小)填充结构并将它们放入一个向量。然后迭代保存每个字段的最大尺寸的向量。然后你知道每个字段的最大尺寸,并且你可以格式化这些线条,使它们在第二遍中对齐并正确分隔。 – Duck

回答

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; 
} 
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*。它使一切复杂化,需要手动内存管理,将会是异常 - 在某些时候不安全,会使调用你的函数的人感到困惑,并使你的代码完全无法维护。

+0

我需要它是C字符串。它必须传递给send()函数。顺便说一句,有没有更好的方法来做到这一点?我的代码非常混乱和可怕。每当我处理字符串,特别是C字符串时,我都会弄得这个混乱。 – user2418202

+0

如果你不得不将它传递给'send()'函数,只需将它转换为一个'char const *'_at那个point_('std :: string foo = file_info(“file”); send(foo.c_str ));')。 'file_info'中不需要这样做。在存在C字符串时出现乱码的问题可以通过尽可能避免使用C字符串来轻松解决。 – rightfold

+0

我应该避免使用C字符串吗?即使对于高级程序员来说,处理每个人都很难吗? – user2418202

1

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

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

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

其中说:“嘿,你会被打印接下来的事情必须n字符”。这就是你想要的。当你将要印刷的东西更长时,这个n它将被全部印刷。没有剪裁或类似的东西。

+0

您可以将setw(int n)附加到字符串,或字符串流或char *吗?我需要把它变成一个字符串对象,而不是输出它。 – user2418202

1

如果你绝对必须使用以null结尾的C-Strings,而不是使用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提供了一个固定长度的参数,其中包含%“数字位数”。

参见:要打印printf reference

字符的最小数量。如果要打印的值 小于此数字,则结果将填充空白。 即使结果较大,值也不会被截断。

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

char buffer[256]; 
file_info(file, buffer); 
printf("%s\n", buffer);