根据文件中的指令编写char数组

时间:2011-11-27 21:42:51

标签: c++ arrays string file char

我需要填充一个char数组,使它看起来像这样:

char* str[3] = {"tex.png", "text2.png", "tex3.png"};`

我需要从一个看起来像这样的文件加载所有内容:

TEXDEF 0 Resources/Textures/tex.png

TEXDEF 1 Resources/Textures/tex2.png

TEXDEF 2 Resources/Textures/tex3.png

到目前为止,我有:

char* texs[3];
char* tstr;
int tnum;

sscanf_s(oneline, "TEXDEF %d %s", &tnum, &tstr);

texs[tnum] = tstr;  // Problem?

我的问题似乎发生在最后一行。编译器没有给我任何错误,但是当我运行程序时,它会导致一个未处理的异常并指向该行。

我该如何解决这个问题?

5 个答案:

答案 0 :(得分:3)

  

我需要填充一个char数组,使它看起来像这样:

不,你没有。这是C ++,因此请使用std::string

std::array<std::string, 3> filenames;

std::ifstream infile("thefile.txt");
std::string line;

for (unsigned int i = 0; std::getline(infile, line); ++i)
{
  std::string tok1, tok3;
  unsigned int tok2;

  if (!(infile >> tok1 >> tok2 >> tok3)) { /* input error! */ }

  if (tok1 != "TEXDEF" || tok2 != i || i > 2) { /* format error */ }

  filenames[i] = tok3;
}

如果文件名的数量是可变的,您只需将数组替换为std::vector<std::string>并省略i > 2范围检查。

答案 1 :(得分:2)

基本上,您的程序崩溃了,因为您从不为字符数组分配内存。此外,sscanf_s()期望格式字符串中的每个%s标记有两个参数。它需要一个指向缓冲区的指针和缓冲区的大小(这是为了避免缓冲区溢出)。

你必须将一个字符数组的指针传递给sscanf_s(),例如:

char tstr[3][MAX_PATH]; // replace `MAX_PATH` by proper maximum size.
sscanf_s(oneline, "TEXDEF %d %s", &tnum, tstr[0], MAX_PATH);
sscanf_s(oneline, "TEXDEF %d %s", &tnum, tstr[1], MAX_PATH);
sscanf_s(oneline, "TEXDEF %d %s", &tnum, tstr[2], MAX_PATH);

然而,手工管理确实很痛苦。使用std::vector<>std::stringstd::ifstream可能会更容易,因为内存会自动管理。

std::ifstream file("path/to/file.txt");
std::vector<std::string> inputs;
// assuming one entry on each line.
for (std::string line; std::getline(file,line); )
{
    // extract components on the line.
    std::istringstream input(line);
    std::string texdef;
    int index = 0;
    std::string path;
    input >> texdef;
    input >> index;
    std::getline(input, path);
    // if the results may appear out of order,
    // insert at `index` instead of at the end.
    inputs.push_back(path);
}

答案 2 :(得分:1)

基于提升精神的强制性答案:

主:

typedef std::map<size_t, std::string> Result;

// ...
const std::string input = // TODO read from file :)
    "TEXDEF 1 Resources/Textures/tex2.png\n"
    "TEXDEF 0 Resources/Textures/tex.png\n"
    "TEXDEF 2 Resources/Textures/tex3.png";

Result result;
if (doTest(input, result))
{
    std::cout << "Parse results: " << std::endl;

    for (Result::const_iterator it = result.begin(); it!= result.end(); ++it)
        std::cout << "Mapped: " << it->first << " to " << it->second << std::endl;
}

输出:

Parse results: 
Mapped: 0 to Resources/Textures/tex.png
Mapped: 1 to Resources/Textures/tex2.png
Mapped: 2 to Resources/Textures/tex3.png

完整代码:

#include <string>
#include <map>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>

namespace qi = boost::spirit::qi;

typedef std::map<size_t, std::string> Result;

template <typename Iterator, typename Skipper> struct TexDefs
  : qi::grammar<Iterator, Result(), Skipper>
{
    TexDefs()
      : TexDefs::base_type(texdefs)
    {
        texdefs  = def >> *(qi::eol >> def);
        def      = "TEXDEF" >> key >> filename;
        key      = qi::uint_;
        filename = qi::lexeme [ +(qi::char_ - qi::eol) ];
    }
    typedef Result::key_type    key_t;
    typedef Result::mapped_type value_t;
    qi::rule<Iterator, Result(), Skipper>        texdefs;
    qi::rule<Iterator, std::pair<key_t, value_t>(), Skipper> def;
    qi::rule<Iterator, key_t(), Skipper>         key;
    qi::rule<Iterator, value_t(), Skipper>       filename;
};

template <typename Input, typename Skip>
   bool doTest(const Input& input, Result& into, const Skip& skip)
{
    typedef typename Input::const_iterator It;
    It first(input.begin()), last(input.end());

    TexDefs<It, Skip> parser;

    bool ok = qi::phrase_parse(first, last, parser, skip, into);

    if (!ok)         std::cerr << "Parse failed at '" << std::string(first, last) << "'" << std::endl;
    if (first!=last) std::cerr << "Warning: remaining unparsed input: '" << std::string(first, last) << "'" << std::endl;

    return ok;
}

template <typename Input>
bool doTest(const Input& input, Result& into)
{
    // allow whitespace characters :)
    return doTest(input, into, qi::char_(" \t"));
}

int main(int argc, const char *argv[])
{
    const std::string input = // TODO read from file :)
        "TEXDEF 1 Resources/Textures/tex2.png\n"
        "TEXDEF 0 Resources/Textures/tex.png\n"
        "TEXDEF 2 Resources/Textures/tex3.png";

    Result result;
    if (doTest(input, result))
    {
        std::cout << "Parse results: " << std::endl;

        for (Result::const_iterator it = result.begin(); it!= result.end(); ++it)
            std::cout << "Mapped: " << it->first << " to " << it->second << std::endl;
    }
}

答案 3 :(得分:0)

读入字符串时,必须准备一个缓冲区并将指向该缓冲区的指针传递给sscanf_s。传递char *变量的地址将不起作用。此外,您应该使用长度限制形式,例如,%255s用于256字节缓冲区。

答案 4 :(得分:0)

尝试使用[basic] C ++:

std::ifstream myfile ("example.txt");
std::vector<std::string> lines;

if(myfile.is_open())
{
    for(std::string line; std::getline(myfile, line); )
    {
        lines.push_back(line);
    }

    myfile.close();
}
else
{
    cout << "Unable to open file";
}

要解析和打印数据,只需像数组一样遍历lines

std::map<int, std::string> data;

for(size_t i = 0; i < lines.length(); ++i)
{
    int n;
    std::string s;
    std::stringstream ss;

    ss << lines[i].substr(((static std::string const)"TEXDEF ").length());
    ss >> n >> s;

    data[n] = s;

    // Print.
    std::cout << lines[i] << "\n";
}

std::cout << std::endl;

我建议你阅读this std::map tutorial


  

资源

     

Basic File I/O
  std::map

相关问题