如何以漂亮的格式放置不同的 C 字符串

how to put different C strings in a pretty format?

本文关键字:字符串 格式 漂亮      更新时间:2023-10-16

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

每个文件有两个 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 = '';
        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) = '';
        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;
    }
}

但它没有用,我用琴弦工作得很差。

这是问题所在:

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

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

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

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

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

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

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

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

如果你绝对

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

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

而是使用按引用调用,不返回任何内容。喜欢这个:

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 = '';
        sprintf(buffer, "%10s%10s%d", file, lm, sb.st_size);
    }
}

要解决格式化问题,您还可以使用 strlen()(但不是 sizeof())并根据 lm 和文件的长度使用空格。但是 sprintf 提供了一个固定长度的参数,其中包含 %"位数"。

另请参阅:打印参考

要打印的最小字符数。如果要打印的值 小于此数字,则结果填充空格。 即使结果更大,也不会截断该值。

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

char buffer[256];
file_info(file, buffer);
printf("%sn", buffer);

谢谢大家的回答。

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

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

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

谢谢。

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) = '';
        string spacing = "                                  ";
        ss << file << spacing.substr(0, spacing.size() - strlen(file)) << lastmod << spacing.substr(0, spacing.size() - lastmod.size()) << sb.st_size << 'n';
    }
    return;
}