2

現在のディレクトリのディレクトリ インデックスを作成する簡単なプログラムを作成しています。

各ファイルには、ファイル名と最終変更時刻用の 2 つの char* オブジェクトと、ファイル サイズ用の 1 つの整数があります。

これらすべてを 1 つの大きなstringまたはchar*.

#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

null で終わる C-String を絶対に使用する必要がある場合は、std::stringstream の代わりにsprintfを使用してください。このように 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 = '\0';
        sprintf(buffer, "%10s%10s%d", file, lm, sb.st_size);
    }
}

フォーマットの問題を解決するには、strlen() (sizeof() ではなく) を使用し、lm とファイルの長さに応じて空白を使用することもできます。しかし、sprintf は %"number of digits"s を持つ固定長のパラメータを提供します。

参照: printf リファレンス

印刷する最小文字数。出力する値がこの数値よりも短い場合、結果は空白スペースで埋められます。結果の方が大きくても値は切り捨てられません。

ただし、この関数を呼び出す前に char* バッファーにメモリを割り当て、sprintf 文字列 (!) に対して十分な大きさであることを確認する必要があります。

すなわち

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

2 つの異なる問題があります。const char *まず、スタック割り当てされた関数から戻ることは明らかにできません。したがって、ヒープに割り当てる必要があります。そして、これが問題です。所有権の問題です。この文字列はどこにありますdeleteか? を使えば簡単に解決できますstd::string

2番目の問題はあなたの質問です。これをうまく整列させる方法。あなたの方法を使用すると、事前に割り当てられた文字列よりも長いファイル名を出力できません。簡単な解決策があります。ヘッダーiomanipには関数が定義されています

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

「ねえ、次に印刷するものはn文字の長さでなければなりません」と言います。そして、これはあなたが望むものです。印刷するものがこれよりも長い場合は、nすべて印刷されます。トリミングなどはありません。

于 2013-11-05T07:33:23.250 に答える
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 に答える