2

I cant write a words from a file to an array.

I have tried to use char and strings, but i have problem with both of them.

FILE *file = fopen("films.txt", "r");
string FILMS[500];
while (!feof(file))
{
    fscanf(file, "%s", FILMS);
    //fgets(FILMS, 500, file);
}

I expect that in each cell there will be a word.

4
  • Dangerous code, prone to security breaches. Commented Aug 2, 2019 at 8:56
  • why arent you using any c++ when this is supposed to be c++ ? Commented Aug 2, 2019 at 8:57
  • well, you are using string but thats not how you can read a string from a file... Commented Aug 2, 2019 at 8:58
  • 1
    Please also read Why is “while (!feof(file))” always wrong? Commented Aug 2, 2019 at 8:59

3 Answers 3

1

Use the C++ classes and functions to make it easier. Instead of a fixed C style array of exactly 500 films, use a std::vector<std::string>> that will grow dynamically when you put film titles in it.

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> get_films() {
    std::ifstream file("films.txt");
    std::vector<std::string> FILMS;
    if(file) { // check that the file was opened ok
        std::string line;
        // read until getline returns file in a failed/eof state
        while(std::getline(file, line)) {
            // move line into the FILMS vector
            FILMS.emplace_back(std::move(line));
            // make sure line is in a specified state again
            line.clear();
        }
    }
    return FILMS;
} // an fstream is automatically closed when it goes out of scope

int main() {
    auto FILMS = get_films();
    std::cout << "Read " << FILMS.size() << " film titles\n";
    for(const std::string& film : FILMS) {
        std::cout << film << "\n";
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

if use std::string and std::vector then might as well use std::copy
Actually simply push_back (copy) instead of move would be more efficient in this case. You want to keep re-using line as a buffer to avoid costly reallocations.
I like both proposals. A std::copy is nice and using copy may be more efficient. I haven't compared the two actuallly ... Can we get figures on just how much more effficient that'd be?
0

As I'm not sure why you tried using c style arrays and files, I posted a 'not too elegant' solution like that one, too, hoping it might help. You could always try to make it more dynamic with some malloc (or new), but I sticked with the easy solution for now.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

void readcpp(const char* fname, std::vector<std::string>& data)
{
    std::ifstream file_in(fname, std::ios::in);

    if (file_in.is_open())
    {
        std::string film;

        while (std::getline(file_in, film))
        {
            data.push_back(film);
        }

        file_in.close();
    }
    else std::cerr << "file cant be opened" << std::endl;
}

#include <cstdio>
#include <cstdlib>
#include <cstring>

void readc(const char* fname, char data[500][500])
{
    FILE* file_in = fopen(fname, "r");

    if (file_in)
    {
        char film[500];

        for (unsigned int i = 0; fgets(film, 500, file_in) && i < 500; i++)
        {
            memcpy(data + i, film, 500);
        }

        fclose(file_in);
    }
    else fprintf(stderr, "file cant be opened\n");
}

int main()
{
    const char* fname = "films.txt";
    char cFilms[500][500];
    std::vector<std::string> cppFilms;

    readc(fname, cFilms);
    readcpp(fname, cppFilms);

    return 0;
}

And as the others mentioned before, do not use feof or for that matter, ifstream's eof member function either, for checking wheter you reached the end of file, as it may be unsafe.

Comments

0

Hm, I see a lot of code in answers.

The usage of algorithm will drastically reduce coding effort.

Additionally it is a "more modern" C++ approach.

The OP said, that he want to have words in some array. OK.

So we will use a std::vector<std::string> for storing those words. As you can see in cppreference, the std::vector has many different constructors. We will use number 4, the range constructor.

This will construct the vector with a range of similar data. The similar data in our case are words or std::string. And we would like to read the complete range of the file, beginning with the first word and ending with the last word in the file.

For iterating over ranges, we use iterators. And for iterating of data in files, we use the std::istream_iterator. We tell this function what we want to read as template parameter, in our case a std::string. Then we tell it, from which file to read.

Since we do not have files on SO, I use a std::istringstream. But that's the same reading from a std::ifstream. If you have na open file stream, then you can hand it over to the std::istream_iterator.

And the result of using this C++ algorithms is that we read the complete file into the vector by just defining the varaible with its constructer as a one-liner.

We do similar for the debug output.

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <sstream>

std::istringstream filmFile{ R"(Film1 Film2
   Film3  Film4 Film5
Film6
)" };

int main()
{
    // Define the variable films and use its range constructor
    std::vector<std::string> films{ std::istream_iterator<std::string>(filmFile), std::istream_iterator<std::string>() };

    // For debug pruposes, show result on console
    std::copy(films.begin(), films.end(), std::ostream_iterator<std::string>(std::cout, "\n"));

    return 0;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.