如何将文件的第一行读入字符数组?

huangapple go评论141阅读模式
英文:

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 &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;cstring&gt;
#include &lt;string&gt;

const int NUM_QUESTIONS = 20;

using namespace std;

int main() {
    // Vars
    char answers[NUM_QUESTIONS];
    ifstream infile;

    // Open File
    infile.open(&quot;Ch8_Ex6Data.txt&quot;);

    infile.getline(answers, NUM_QUESTIONS);
    cout &lt;&lt; answers &lt;&lt; endl;
    infile.getline(answers, NUM_QUESTIONS);
    cout &lt;&lt; answers &lt;&lt; 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 &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;cstring&gt;
#include &lt;string&gt;

const int NUM_QUESTIONS = 20;

using namespace std;

int main() {
    // Vars
    char answers[NUM_QUESTIONS];
    ifstream infile;

    // Open File
    infile.open(&quot;Ch8_Ex6Data.txt&quot;);

    // Read first line into character array
    infile.getline(answers, &#39;\n&#39;);
    cout &lt;&lt; answers;

    return 0;
}

Which outputs:

TTFTFTTTF

Which clearly isn't the whole line.

What should I do from here?

答案1

得分: 2

你可以使用 std::ifstreamstd::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(&quot;filename&quot;);

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::stringstd::vectorrange 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 &lt;iostream&gt;
#include &lt;sstream&gt; 
//#include &lt;cstring&gt; not needed
#include &lt;string&gt;
#include &lt;vector&gt;
//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&lt;answer_t&gt; student_answers;
};
// make functions
exam_data_t load_exam_data(std::istream&amp; 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
{
&quot;TTFTFTTTFTFTFFTTFTTF\n&quot;
&quot;ABC54102 T FTFTFTTTFTTFTTF TF\n&quot;
&quot;DEF56278 TTFTFTTTFTFTFFTTFTTF\n&quot;
&quot;ABC42366 TTFTFTTTFTFTFFTTF\n&quot;
&quot;ABC42586 TTTTFTTT TFTFFFTF\n&quot;
};
//std::ifstream input_file{ &quot;Ch8_Ex6Data.txt&quot; };
auto exam_data = load_exam_data(input_file);
std::cout &lt;&lt; &quot;correct answers : &quot; &lt;&lt; exam_data.correct_answers &lt;&lt; &quot;\n&quot;;
for (const auto&amp; answer : exam_data.student_answers)
{
std::cout &lt;&lt; &quot;Student : &quot; &lt;&lt; answer.student_id &lt;&lt; &quot;, answer = &quot; &lt;&lt; answer.input &lt;&lt; &quot;\n&quot;;
}
return 0;
}

答案4

得分: 0

std::istream::getline 确保提取的数据以一个空字符终止。这使得在给定大小为 20 的缓冲区的情况下,无法从流中提取 20 个字符进行写入。(您可能会注意到行尾的 F 缺失。)

您有几个选项:

  1. 增加缓冲区大小 1 个字符。
  2. 使用 read 而不是 getline。我只建议在确切要提取的字符数已知或已验证输入读取只包含 &#39;T&#39;&#39;F&#39; 时才这样做。
  3. 使用 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:

  1. Increase the buffer size by 1
  2. Use read instead of getline. 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 &#39;T&#39; and &#39;F&#39; anyways.
  3. Use getline, ignore the fail bit being set, and then extract another char using get. (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&lt;class F&gt;
void RunExample(char const* functionName, F&amp;&amp; readLine)
{
std::istringstream in(&quot;TTFTFTTTFTFTFFTTFTTF\nFFTFTFFFTFTFTTFFTFFT&quot;);
std::cout &lt;&lt; &quot;Running &quot; &lt;&lt; functionName &lt;&lt; &#39;\n&#39;;
readLine(in, std::cout);
readLine(in, std::cout);
}
int main() {
RunExample(&quot;getline(increased buffer size)&quot;, [](std::istream&amp; in, std::ostream&amp; out) // 1.
{
char buffer[NumQuestions + 1];
in.getline(buffer, NumQuestions + 1, &#39;\n&#39;);
assert(in.gcount() &gt;= NumQuestions);
out &lt;&lt; std::string_view(buffer, NumQuestions) &lt;&lt; &#39;\n&#39;;
});
RunExample(&quot;read+ignore&quot;, [](std::istream&amp; in, std::ostream&amp; out) // 2.
{
char buffer[NumQuestions];
in.read(buffer, NumQuestions);
in.ignore(1, &#39;\n&#39;);
out &lt;&lt; std::string_view(buffer, NumQuestions) &lt;&lt; &#39;\n&#39;;
});
RunExample(&quot;getline+get+ignore&quot;, [](std::istream&amp; in, std::ostream&amp; out) // 3.
{
char buffer[NumQuestions];
in.getline(buffer, NumQuestions, &#39;\n&#39;);
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 != &#39;\n&#39;);
assert(lastChar != std::istream::traits_type::eof());
buffer[NumQuestions - 1] = lastChar;
in.ignore(1, &#39;\n&#39;); // skip newline after the input just extracted, if present
out &lt;&lt; std::string_view(buffer, NumQuestions) &lt;&lt; &#39;\n&#39;;
});
}

huangapple
  • 本文由 发表于 2023年6月8日 08:15:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427840.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定