根据文件中的指令写入字符数组
Writing a char array based on instructions from a file
我需要填充一个字符数组,使它看起来像这样:
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?
我的问题出现在最后一行。编译器没有给我任何错误,但是当我运行程序时,它会导致一个未处理的异常,并指向那一行。
我该如何解决这个问题?
我需要填充一个字符数组,使它看起来像这样:
不,你没有。这是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
范围检查
基本上,您的程序正在崩溃,因为您从未为您的字符数组分配内存。此外,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);
}
基于Boost Spirit的必选答案:
主:typedef std::map<size_t, std::string> Result;
// ...
const std::string input = // TODO read from file :)
"TEXDEF 1 Resources/Textures/tex2.pngn"
"TEXDEF 0 Resources/Textures/tex.pngn"
"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.pngn"
"TEXDEF 0 Resources/Textures/tex.pngn"
"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;
}
}
读入字符串时,必须准备一个缓冲区,并将指向该缓冲区的指针传递给sscanf_s
。传递char *
变量的地址将不起作用。此外,您应该使用长度限制的形式,例如,对于256字节的缓冲区,%255s
。
尝试使用[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;
我建议你阅读这个std::map
教程。
基本文件I/O
std::map
相关文章:
- 指向指向字符数组的指针数组的指针
- 比较字符数组
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- 使用无符号字符数组有效存储内存
- 错误:字符数组的初始值设定项太多
- 对字符数组中的元素执行逐位操作
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 如何在 C++ 中从文件中读取字符数组(带有一些空格)
- C++ 传递二维字符数组
- 无法在 C++ 中输入字符数组
- 字符数组中的元素数
- 我的目标是编写一个程序来计算和存储字符串在字符数组中出现的位置
- 使用字符数组作为 Map 中的键
- C++:__aligned(__alignof__) 导致字符数组数据出现问题?
- 按顺序声明的字符数组重叠
- 在 C++ 中字符串的大小与字符数组的大小
- 寻找一种更好的方法来表示无符号字符数组
- 如何打印 2D 字符数组C++
- 从字符数组的元素中减去'a'是什么意思
- 我是否不正确地集中了这些字符数组?