我需要填充一个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?
我的问题似乎发生在最后一行。编译器没有给我任何错误,但是当我运行程序时,它会导致一个未处理的异常并指向该行。
我该如何解决这个问题?
答案 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::string
和std::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。
资源