英文:
How can I read the first line of a file into a character array?
问题
你可以尝试使用getline()
函数来读取整行文本,然后从该行中提取所需的答案部分。这是一个可能的C++代码示例:
#include <iostream>
#include <fstream>
#include <string>
const int NUM_QUESTIONS = 20;
using namespace std;
int main() {
// Vars
char answers[NUM_QUESTIONS];
ifstream infile;
string line;
// Open File
infile.open("Ch8_Ex6Data.txt");
// Read the first line into a string
getline(infile, line);
// Copy the characters from the string to the character array
for (int i = 0; i < NUM_QUESTIONS; i++) {
if (i < line.length()) {
answers[i] = line[i];
} else {
// Handle the case where the line is shorter than NUM_QUESTIONS
answers[i] = ' '; // You can use any placeholder value
}
}
// Print the answers
for (int i = 0; i < NUM_QUESTIONS; i++) {
cout << answers[i];
}
return 0;
}
这段代码会将第一行的答案键读取到字符数组answers
中,即使该行不足20个字符,也会使用空格进行填充。然后,你可以使用answers
数组进行进一步的比较和处理。
英文:
I am doing a textbook exercise that requires scoring student tests.
The input file looks like:
TTFTFTTTFTFTFFTTFTTF
ABC54102 T FTFTFTTTFTTFTTF TF
DEF56278 TTFTFTTTFTFTFFTTFTTF
ABC42366 TTFTFTTTFTFTFFTTF
ABC42586 TTTTFTTT TFTFFFTF
The first line is the answer key for a test, and the following lines are student IDs and their responses, with blanks as an unanswered question.
The very first thing I need to do is read the first line so that I have something to compare the responses to. My first thought is to use a character array, but I can't seem to get it right. The first method I tried is:
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
const int NUM_QUESTIONS = 20;
using namespace std;
int main() {
// Vars
char answers[NUM_QUESTIONS];
ifstream infile;
// Open File
infile.open("Ch8_Ex6Data.txt");
infile.getline(answers, NUM_QUESTIONS);
cout << answers << endl;
infile.getline(answers, NUM_QUESTIONS);
cout << answers << endl;
return 0;
}
Which outputs
TTFTFTTTFTFTFFTTFTT
This is the all of the answers, but I noticed I couldn't do this twice to get to the next line. The second getline() sees an empty string.
The second method I tried was:
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
const int NUM_QUESTIONS = 20;
using namespace std;
int main() {
// Vars
char answers[NUM_QUESTIONS];
ifstream infile;
// Open File
infile.open("Ch8_Ex6Data.txt");
// Read first line into character array
infile.getline(answers, '\n');
cout << answers;
return 0;
}
Which outputs:
TTFTFTTTF
Which clearly isn't the whole line.
What should I do from here?
答案1
得分: 2
你可以使用 std::ifstream
和 std::getline()
来实现这个。
首先,创建一个新的输入文件流并初始化为文件:
std::ifstream file("文件名");
然后,获取一行内容:(getline()
函数将读取直到换行符)
std::string s;
std::getline(file, s);
如果你需要将其作为字符数组使用,可以使用 std::string.c_str()
将其转换为C风格字符串。
英文:
You can use the std::ifstream
and std::getline()
for this.
First, create a new input file stream and initialize with the file:
std::ifstream file("filename");
Then, get the line: (The getline()
function will read all until a newline character)
std::string s;
std::getline(file, s);
Then, if you need it as a character array, you can use std::string.c_str()
to convert into C style string.
答案2
得分: 0
只要快速查看您的代码,看起来您正在使用一个20个字符的数组来存储TTFTFTTTFTFTFFTTFTTF,这正好是20个字符。
getline函数将读取一个字符串,该字符串应始终以null或\n字符结尾,因此为了读取您的20个字符的字符串,您的数组大小实际上应为21。尝试更改为const int NUM_QUESTIONS = 20;
英文:
Just with a quick look at yuour code, it looks like you are using a 20 character array to store
TTFTFTTTFTFTFFTTFTTF
which is exactly 20 characters
getline function will read a string which should always end with a null
or \n
character, so to read your string of 20 characters yours array size should actually 21. Try changing to
const int NUM_QUESTIONS = 20;
答案3
得分: 0
这是如何读取文件的开始。在实际应用中,您需要添加更多的错误处理(永远不要相信程序的输入)。
函数和变量的命名非常重要,这样您可以像阅读一本书(或至少是一本食谱)一样阅读最终的代码。
构建块:std::string,std::vector,range based for。
还要注意的是,不是从通用流类加载,而是从文件流加载。这将使您的代码更具可重用性(现在它可以从任何流中加载,包括内存中的流)。
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
//const int NUM_QUESTIONS = 20;
//使用vector时不需要,可以在运行时适应输入大小
// using namespace std; 不要使用这个。
// 然后模型化您的输入
struct answer_t
{
std::string student_id;
std::string input;
};
struct exam_data_t
{
std::string correct_answers;
std::vector<answer_t> student_answers;
};
// 创建函数
exam_data_t load_exam_data(std::istream& stream)
{
exam_data_t answers;
std::getline(stream, answers.correct_answers);
// 添加更多的输入验证,答案文本长度应等于正确答案的长度等...
std::string line;
while (std::getline(stream, line))
{
answer_t answer;
// 基于假设的简单分割行
// 输入是正确的(通常在实践中不成立!)
answer.student_id = line.substr(0ul, 8ul);
answer.input = line.substr(10ul);
answers.student_answers.push_back(answer);
}
return answers;
}
int main()
{
// 模拟输入文件
std::istringstream input_file
{
"TTFTFTTTFTFTFFTTFTTF\n"
"ABC54102 T FTFTFTTTFTTFTTF TF\n"
"DEF56278 TTFTFTTTFTFTFFTTFTTF\n"
"ABC42366 TTFTFTTTFTFTFFTTF\n"
"ABC42586 TTTTFTTT TFTFFFTF\n"
};
//std::ifstream input_file{ "Ch8_Ex6Data.txt" };
auto exam_data = load_exam_data(input_file);
std::cout << "correct answers : " << exam_data.correct_answers << "\n";
for (const auto& answer : exam_data.student_answers)
{
std::cout << "Student : " << answer.student_id << ", answer = " << answer.input << "\n";
}
return 0;
}
英文:
This is the beginning on how to read a file. In practice you would need to add a lot more error handling though (never trust your programs input).
Naming of functions and variables is very important to so you can read the final code like a book (or at least a recipe)
Building blocks : std::string, std::vector, range based for.
Also not loading is done from a generic stream class not a filestream. This will make your code more reusable (it can load from any stream now, also those in memory).
#include <iostream>
#include <sstream>
//#include <cstring> not needed
#include <string>
#include <vector>
//const int NUM_QUESTIONS = 20;
//not needed with vector you can adapt to the input size at runtime
// using namespace std; NO Unlearn this.
// then model your input
struct answer_t
{
std::string student_id;
std::string input;
};
struct exam_data_t
{
std::string correct_answers;
std::vector<answer_t> student_answers;
};
// make functions
exam_data_t load_exam_data(std::istream& stream)
{
exam_data_t answers;
std::getline(stream, answers.correct_answers);
// toda add more input validation, answer text lengths
// should be equal to length of correct_answers etc...
std::string line;
while (std::getline(stream, line))
{
answer_t answer;
// simple split line based on assumption that
// input is correct (usually not true in practice!)
answer.student_id = line.substr(0ul, 8ul);
answer.input = line.substr(10ul);
answers.student_answers.push_back(answer);
}
return answers;
}
int main()
{
// simulate input file
std::istringstream input_file
{
"TTFTFTTTFTFTFFTTFTTF\n"
"ABC54102 T FTFTFTTTFTTFTTF TF\n"
"DEF56278 TTFTFTTTFTFTFFTTFTTF\n"
"ABC42366 TTFTFTTTFTFTFFTTF\n"
"ABC42586 TTTTFTTT TFTFFFTF\n"
};
//std::ifstream input_file{ "Ch8_Ex6Data.txt" };
auto exam_data = load_exam_data(input_file);
std::cout << "correct answers : " << exam_data.correct_answers << "\n";
for (const auto& answer : exam_data.student_answers)
{
std::cout << "Student : " << answer.student_id << ", answer = " << answer.input << "\n";
}
return 0;
}
答案4
得分: 0
std::istream::getline
确保提取的数据以一个空字符终止。这使得在给定大小为 20 的缓冲区的情况下,无法从流中提取 20 个字符进行写入。(您可能会注意到行尾的 F
缺失。)
您有几个选项:
- 增加缓冲区大小 1 个字符。
- 使用
read
而不是getline
。我只建议在确切要提取的字符数已知或已验证输入读取只包含'T'
和'F'
时才这样做。 - 使用
getline
,忽略设置的 fail 位,然后使用get
提取另一个字符。(不建议,因为这会导致代码不如其他选项易读。)
以下代码演示了所有这些选项:
constexpr size_t NumQuestions = 20;
template<class F>
void RunExample(char const* functionName, F&& readLine)
{
std::istringstream in("TTFTFTTTFTFTFFTTFTTF\nFFTFTFFFTFTFTTFFTFFT");
std::cout << "Running " << functionName << '\n';
readLine(in, std::cout);
readLine(in, std::cout);
}
int main() {
RunExample("getline(increased buffer size)", [](std::istream& in, std::ostream& out) // 1.
{
char buffer[NumQuestions + 1];
in.getline(buffer, NumQuestions + 1, '\n');
assert(in.gcount() >= NumQuestions);
out << std::string_view(buffer, NumQuestions) << '\n';
});
RunExample("read+ignore", [](std::istream& in, std::ostream& out) // 2.
{
char buffer[NumQuestions];
in.read(buffer, NumQuestions);
in.ignore(1, '\n');
out << std::string_view(buffer, NumQuestions) << '\n';
});
RunExample("getline+get+ignore", [](std::istream& in, std::ostream& out) // 3.
{
char buffer[NumQuestions];
in.getline(buffer, NumQuestions, '\n');
assert(in.gcount() == (NumQuestions - 1));
assert(!in.bad());
in.clear(); // remove fail bit set since the delimiter is not encountered before exhausting the buffer storage
auto const lastChar = in.get();
assert(lastChar != '\n');
assert(lastChar != std::istream::traits_type::eof());
buffer[NumQuestions - 1] = lastChar;
in.ignore(1, '\n'); // skip newline after the input just extracted, if present
out << std::string_view(buffer, NumQuestions) << '\n';
});
}
英文:
std::istream::getline
ensures the extracted data is terminated by a 0 char. This makes extracting 20 chars from the stream given a buffer of size 20 to write to impossible. (You may realize that the F
at the end of the line is missing.)
You've got several options here:
- Increase the buffer size by 1
- Use
read
instead ofgetline
. I only recommend doing this, if the exact number of chars to extract is known or you've validating that the input read contains only'T'
and'F'
anyways. - Use
getline
, ignore the fail bit being set, and then extract another char usingget
. (Not recommended, since this makes for code that isn't as easy to read as the other options.)
The following code demonstrates all of those options:
constexpr size_t NumQuestions = 20;
template<class F>
void RunExample(char const* functionName, F&& readLine)
{
std::istringstream in("TTFTFTTTFTFTFFTTFTTF\nFFTFTFFFTFTFTTFFTFFT");
std::cout << "Running " << functionName << '\n';
readLine(in, std::cout);
readLine(in, std::cout);
}
int main() {
RunExample("getline(increased buffer size)", [](std::istream& in, std::ostream& out) // 1.
{
char buffer[NumQuestions + 1];
in.getline(buffer, NumQuestions + 1, '\n');
assert(in.gcount() >= NumQuestions);
out << std::string_view(buffer, NumQuestions) << '\n';
});
RunExample("read+ignore", [](std::istream& in, std::ostream& out) // 2.
{
char buffer[NumQuestions];
in.read(buffer, NumQuestions);
in.ignore(1, '\n');
out << std::string_view(buffer, NumQuestions) << '\n';
});
RunExample("getline+get+ignore", [](std::istream& in, std::ostream& out) // 3.
{
char buffer[NumQuestions];
in.getline(buffer, NumQuestions, '\n');
assert(in.gcount() == (NumQuestions - 1));
assert(!in.bad());
in.clear(); // remove fail bit set since the delimiter is not encountered before exhausting the buffer storage
auto const lastChar = in.get();
assert(lastChar != '\n');
assert(lastChar != std::istream::traits_type::eof());
buffer[NumQuestions - 1] = lastChar;
in.ignore(1, '\n'); // skip newline after the input just extracted, if present
out << std::string_view(buffer, NumQuestions) << '\n';
});
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论