Filling a cstring using <cstring> with text from a textfile using File I/O C++ - c++

I began learning strings yesterday and wanted to manipulate it around by filling it with a text from a text file. However, upon filling it the cstring array only prints out the last word of the text file. I am a complete beginner, so I hope you can keep this beginner friendly. The lines I want to print from the file are:
"Hello World from UAE" - First line
"I like to program" - Second line
Now I did look around and eventually found a way and that is to use std::skipary or something like that but that did not print it the way I had envisioned, it prints letter by letter and skips each line in doing so.
here is my code:
#include <fstream>
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
int main() {
ifstream myfile;
myfile.open("output.txt");
int vowels = 0, spaces = 0, upper = 0, lower = 0;
//check for error
if (myfile.fail()) {
cout << "Error opening file: ";
exit(1);
}
char statement[100];
while (!myfile.eof()) {
myfile >> statement;
}
for (int i = 0; i < 30; ++i) {
cout << statement << " ";
}

I'm not exactly sure what you try to do with output.txt's contents, but a clean way to read through a file's contents using C++ Strings goes like this:
if (std::ifstream in("output.txt"); in.good()) {
for (std::string line; std::getline(in, line); ) {
// do something with line
std::cout << line << '\n';
}
}
You wouldn't want to use char[] for that, in fact raw char arrays are hardly ever useful in modern C++.
Also - As you can see, it's much more concise to check if the stream is good than checking for std::ifstream::fail() and std::ifstream::eof(). Be optimistic! :)

Whenever you encounter output issues - either wrong or no output, the best practise is to add print (cout) statements wherever data change is occurring.
So I first modified your code as follows:
while (!myfile.eof()) {
myfile >> statement;
std::cout<<statement;
}
This way, the output I got was - all lines are printed but the last line gets printed twice.
So,
We understood that data is being read correctly and stored in statement.
This raises 2 questions. One is your question, other is why last line is printed twice.
To answer your question exactly, in every loop iteration, you're reading the text completely into statement. You're overwriting existing value. So whatever value you read last is only stored.
Once you fix that, you might come across the second question. It's very common and I myself came across that issue long back. So I'm gonna answer that as well.
Let's say your file has 3 lines:
line1
line2
line3
Initially your file control (pointer) is at the beginning, exactly where line 1 starts. After iterations when it comes to line3, we know it's last line as we input the data. But the loop control doesn't know that. For all it knows, there could be a million more lines. Only after it enters the loop condition THE NEXT TIME will it come to know that the file has ended. So the final value will be printed twice.

Related

searching a name in the csv file on C++

I am a young programmer who is trying to learn c++. i have a working csv.file. but i want to search for a specific number assigned to the name and then displays the name of what i'm looking for. i have the file here:
1,Bulbasaur,grass
2,Ivysaur, grass
3,Venusaur, grass
4,Charmander, fire
5,Charmeleon, fire
6,Charizard, fire
7,Squirtle, water
8,Wartortle, water
9,Blastoise, water
Code
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ip("pokedex.csv");
string pokedexnum[9];
string pokemonName[9];
string pokemonType[9];
cout<<"please enter a pokemon number:"<<" ";
cin>>pokemonType[0];
while (ip.good()){
getline( ip, pokedexnum[0]);
getline( ip, pokemonName[0]);
getline( ip, pokemonType[0]);
}
cout<<"the pokemon that is:"<< " "<<pokedexnum[0]<< "is the pokemon called:"<< pokemonName[0];
ifstream close("pokedex.csv");
return 0;
}
when it runs
please enter a pokemon number: 1
the pokemon that is: is the pokemon called:8,Wartortle, water
could you please point out what i am doing wrong?
Among the issues in this code:
You're not using std::getline correctly for comma-separated data. The result is each pass is consuming three lines from your input file; not three values from each line.
You're also not using ip.good() correctly as a while-condition.
You're retaining your test value in the array, which will be overwritten on the first iteration pass, so it is lost.
You're ignoring potential IO failures with each std::getline invoke.
You're overwriting slot-0 in your arrays with each loop iteration.
Minor, ifstream close("pokedex.csv"); clearly isn't doing what you think it is. That just creates another fstream object called close on the given file name.
The later may be intentional for now, but clearly broken in the near future.
In reality, you don't need arrays for any of this. All you're doing is reading lines, and seem to want to test the input number against that of the CSV data first column, reporting the line that you find, then ending this.
So do that:
Read the input value to search for.
Open the file for scanning.
Enumerate the file one line at a time.
For each line from (3), use a string stream to break the line into the comma separated values.
Test the id value against the input from (1). If the same, report the result and break the loop; you're done.
The result is something like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
int main()
{
std::cout<<"please enter a pokemon number: ";
long num;
if (std::cin >> num && num > 0)
{
std::ifstream ip("pokedex.csv");
std::string line;
while (std::getline(ip, line))
{
std::istringstream iss(line);
std::string id, name, skill;
if (std::getline(iss, id, ',') &&
std::getline(iss, name, ',') &&
std::getline(iss, skill))
{
char *endp = nullptr;
long n = std::strtol(id.c_str(), &endp, 10);
if (id.c_str() != endp && n == num)
{
std::cout << "The pokemon that is: " << num << " is called: " << name << '\n';
break;
}
}
}
}
}
Admittedly untested, but it should work.
Whether you want to store the items in arrays at this point is entirely up to you, but it isn't needed to solve the somewhat abstract problem you seem to be attempting, namely finding the matching line and reporting the name from said-same. If you still want to store them in arrays, I suggest you craft a structure to do so, something like:
struct Pokemon
{
int id;
std::string name;
std::string skill;
};
and have a single array of those, rather than three arbitrary arrays that must be kept in sync.
Four issues jump out at me:
You store the user's input into pokemonType, but then also use pokemonType for reading data from your CSV file. The file input is going to overwrite the user input.
Your file input loop always references index 0. All of the lines from your data file are going into element 0. That's the main reason that even if the user inputs 1, the output is from the last line of the data file.
Your file reading loop is structured like you want to put one part of each data line into a different array, but what you've written actually reads three lines on every iteration, storing those lines into the three different arrays.
This isn't affecting your output, but the code ifstream close("pokedex.csv"); is written like you want to close the file stream you opened, but I do believe what this line actually does is create a new ifstream called close, and opens pokedex.csv attached to it. In other words, it's just like your other line ifstream ip("pokedex.csv"); but with close as the variable name instead of ip.
You are going to want to look into something called "string tokenization". Start with some web searches, apply what you read about to your code, and of course if you hit another snag, post a new question here to Stack Overflow, showing (as you did here) what you tried and in what way it isn't working.
Elaborating on #3, here's what how your data file is being read:
at the end of the 1st iteration of the file-reading loop, ...
pokedexnum[0] is "1,Bulbasaur,grass"
pokemonName[0] is "2,Ivysaur, grass"
pokemonType[0] is "3,Venusaur, grass"
at the end of the 2nd iteration of the file-reading loop, ...
pokedexnum[0] is "4,Charmander, fire"
pokemonName[0] is "5,Charmeleon, fire"
pokemonType[0] is "6,Charizard, fire"
at the end of the 3rd iteration of the file-reading loop, ...
pokedexnum[0] is "7,Squirtle, water"
pokemonName[0] is "8,Wartortle, water"
pokemonType[0] is "9,Blastoise, water"
And that's why
<< "is the pokemon called:"<< pokemonName[0];
outputs
is the pokemon called:8,Wartortle, water

to find a word from a text file and then also display the line number in which the word lies using C++

I am absolutely a beginner at programming. No this is not a homework either. I am trying to learn it by myself. As stated in the titel itself I would like to input a .txt file and find out a particular word from the file. But thats not exactly what I want. I rather want the line number in which the word lies, so that i can use this line number and print out all the lines in the .txt file after this particular line. I found this code on youtube where it showed me how to find the word. I modified it a bit and its now giving me the line in which the searched word states (NOT THE LINE NUMBER). I am attaching the code.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
string find_word(string file, string word)
{
int offset;
string line1;
ifstream Myfile;
Myfile.open(open);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile, line1);
if ((offset = line1.find(word,o)) != string::npos)
{
return line1;
}
}
Myfile.close();
}
else
cout << "couldn't open...." << endl;
}
int main ()
{
string c = find_word("test.txt", "$COOR");
cout << c;
cin.get();
return 0;
}
right now the text file contains just 8 lines and "$COOR" lies in line 4. the program just gives me the entire line. But I want the line number so that I can print out the lines after line number 4.
I would later like to test it for a file having many lines i.e. more than 50000000 or so.
Think logically. You don't know whether a given line contains the word you're looking for until you read it. Therefore, you always need to know the number of the current line in the text file that you've read, so if the line contains the word, you then print the line number.
You need another variable int, initialized to zero, and incremented every time your code reads a line of text. So, when your code reads the first line of text, it gets incremented to 1. Then, when the code reads the next line of text, the new variable gets incremented to 2, and so on. So, when you find the word, you know where to look to find the line number.
Your code already has a loop for reading each line of text. Don't you think it's now obvious where you will need to increment the line counter?

How to read individual lines of a text file using C++

Ok, so its been a while since i messed with reading and writing file and i have just about forgot everything i learned. So, i am currently just trying to figure out how to read specific lines from a text file and output that said line into the command prompt. Here is my code that i am having issues with:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ifstream input;
int lineN=0;
string line[lineN];
input.open("input.txt");
getline(input, line[lineN]);
cout << line[lineN];
}
As it currently is, it will read the first line of the text file no problem. However, if i change the variable lineN(which stands for line number) to 1 to read the second line, it crashes the prompt. I have no idea what it is i am doing wrong. I have tried researching this problem, but everyone's answer is too vague (That or i'm just too dumb). If you could help me out that would great.
The problem is that you define here an empty array of strings and arrays are not dynamic:
int lineN=0;
string line[lineN];
When you change lineN to 1, nothing changes in the array, and you'll get out of bound !
The bettter way would be to use vectors:
vector<string> line;
Read in a temporary string:
string current_line;
getline(input, current_line);
and add it to your vector:
line.push_back(current_line);
Putting all this in a nice loop would be more useful:
string current_line;
while (getline(input, current_line)) {
line.push_back(current_line);
}
You may access any line later, by using line[i] exactly with your array, as long as i< line.size(). Or you may iterate easily throug all its content:
for (string x : line) { // means for every x in line[]
cout<< x<<endl;
}
you allocate a array of size 0 ...
you will find answer of what will happen can be found here:
C++ new int[0] -- will it allocate memory?

Error reading and printing a text file with C++

I have a bug with my code (the code at the end of the question). The purpose of my C++ executable is to read a file that contains numbers, copy it in a std::vector and
then just print the contents in the stdout? Where is the problem? (atoi?)
I have a simple text file that contains the following numbers (each line has one number)
mini01:algorithms ios$ cat numbers.txt
1
2
3
4
5
When I execute the program I receive one more line:
mini01:algorithms ios$ ./a.out
1
2
3
4
5
0
Why I get the 6th line in the stdout?
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void algorithm(std::vector<int>& v) {
for(int i=0; i < v.size(); i++) {
cout << v[i] << endl;
}
}
int main(int argc, char **argv) {
string line;
std::vector<int> vector1;
ifstream myfile("numbers.txt");
if ( myfile.is_open()) {
while( myfile.good() )
{
getline(myfile, line);
vector1.push_back(atoi(line.c_str()));
}
myfile.close();
}
else {
cout << "Unable to open file" << endl;
}
algorithm(vector1);
return 0;
}
You should not use while (myfile.good()), as it will loop once to many.
Instead use
while (getline(...))
The reason you can't use the flags to check for looping, is that they don't get set until after an input/output operation notices the problem (error or end-of-file).
Don't use good() as the condition of your extraction loop. It does not accurately indicate whether the next read will succeed or not. Move your call to getline into the condition:
while(getline(myfile, line))
{
vector1.push_back(atoi(line.c_str()));
}
The reason it is failing in this particular case is because text files typically have an \n at the end of the file (that is not shown by text editors). When the last line is read, this \n is extracted from the stream. Yes, that may be the very last character in the file, but getline doesn't care to look any further than the \n it has extracted. It's done. It does not set the EOF flag or do anything else to cause good() to return false.
So at the next iteration, good() is still true, the loop continues and getline attempts to extract from the file. However, now there's nothing left to extract and you just get line set to an empty string. This then gets converted to an int and pushed into the vector1, giving you the extra value.
In fact, the only robust way to check if there is a problem with extraction is to check the stream's status bits after extracting. The easiest way to do this is to make the extraction itself the condition.
You read one too many lines, since the condition while is false AFTER you had a "bad read".
Welcome to the wonderful world of C++. Before we go to the bug first, I would advise you to drop the std:: namespace resolution before defining or declaring a vector as you already have
using namespace::std;
A second advise would be to use the pre increment operator ++i instead of i++ wherever feasible. You can see more details on that here.
Coming to your problem in itself, the issue is an empty new line being read at the end of file. A simple way to avoid this would be to check the length of line before using it.
getline(myfile, line);
if (line.size()) {
vector1.push_back(atoi(line.c_str()));
}
This would enable your program now to read a file interspersed with empty lines. To be further foolproof you can check the line read for presence of any non numeric characters before using atoi on it. However the best solution as mentioned would be use to read the line read to the loop evaluation.

Need to write specific lines of a text into a new text

I have numerical text data lines ranging between 1mb - 150 mb in size, i need to write lines of numbers related to heights, for example: heights=4 , new text must include lines: 1,5,9,13,17,21.... consequentially.
i have been trying to find a way to do this for a while now, tried using a list instead of vector which ended up with compilation errors.
I have cleaned up the code as advised. It now writes all lines sample2 text, all done here. Thank you all
I am open to method change as long as it delivers what i need, Thank you for you time and help.
following is what i have so far:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <vector>
using namespace std;
int h,n,m;
int c=1;
int main () {
cout<< "Enter Number Of Heights: ";
cin>>h;
ifstream myfile_in ("C:\\sample.txt");
ofstream myfile_out ("C:\\sample2.txt");
string line;
std::string str;
vector <string> v;
if (myfile_in.is_open()) {
myfile_in >> noskipws;
int i=0;
int j=0;
while (std::getline(myfile_in, line)) {
v.push_back( line );
++n;
if (n-1==i) {
myfile_out<<v[i]<<endl;
i=i+h;
++j;
}
}
cout<<"Number of lines in text file: "<<n<<endl;
}
else cout << "Unable to open file(s) ";
cout<< "Reaching here, Writing one line"<<endl;
system("PAUSE");
return 0;
}
You need to use seekg to set the position at the beginning of the file, once you have read it (you have read it once, to count the lines (which I don't think you actually need, as this size is never used, at least in this piece of code)
And what is the point if the inner while? On each loop, you have
int i=1;
myfile_out<<v[i]; //Not writing to text
i=i+h;
So on each loop, i gets 1, so you output the element with index 1 all the time. Which is not the first element, as indices start from 0. So, once you put seekg or remove the first while, your program will start to crash.
So, make i start from 0. And get it out of the two while loops, right at the beginning of the if-statement.
Ah, the second while is also unnecessary. Leave just the first one.
EDIT:
Add
myfile_in.clear();
before seekg to clear the flags.
Also, your algorithm is wrong. You'll get seg fault, if h > 1, because you'll get out of range (of the vector). I'd advise to do it like this: read the file in the while, that counts the lines. And store each line in the vector. This way you'll be able to remove the second reading, seekg, clear, etc. Also, as you already store the content of the file into a vector, you'll NOT lose anything. Then just use for loop with step h.
Again edit, regarding your edit: no, it has nothing to do with any flags. The if, where you compare i==j is outside the while. Add it inside. Also, increment j outside the if. Or just remove j and use n-1 instead. Like
if ( n-1 == i )
Several things.
First you read the file completely, just to count the number of lines,
then you read it a second time to process it, building up an in memory
image in v. Why not just read it in the first time, and do everything
else on the in memory image? (v.size() will then give you the number
of lines, so you don't have to count them.)
And you never actually use the count anyway.
Second, once you've reached the end of file the first time, the
failbit is set; all further operations are no-ops, until it is reset.
If you have to read the file twice (say because you do away with v
completely), then you have to do myfile_in.clear() after the first
loop, but before seeking to the beginning.
You only test for is_open after having read the file once. This test
should be immediately after the open.
You also set noskipws, although you don't do any formatted input
which would be affected by it.
The final while is highly suspect. Because you haven't done the
clear, you probably never enter the loop, but if you did, you'd very
quickly start accessing out of bounds: after reading n lines, the size
of v will be n, but you read it with index i, which will be n * h.
Finally, you should explicitly close the output file and check for
errors after the close, just in case.
It's not clear to me what you're trying to do. If all you want to do is
insert h empty lines between each existing line, something like:
std::string separ( h + 1, '\n' );
std::string line;
while ( std::getline( myfile_in, line ) ) {
myfile_out << line << separ;
}
should do the trick. No need to store the complete input in memory.
(For that matter, you don't even have to write a program for this.
Something as simple a sed 's:$:\n\n\n\n:' < infile > outfile would do
the trick.)
EDIT:
Reading other responses, I gather that I may have misunderstood the
problem, and that he only wants to output every h-th line. If this is
the case:
std::string line;
while ( std::getline( myfile_in, line ) ) {
myfile_out << line << '\n';
for ( int count = h - 1; h > 0; -- h ) {
std::getline( myfile_in, line );
// or myfile_in.ignore( INT_MAX, '\n' );
}
}
But again, other tools seem more appropriate. (I'd follow thiton's
suggestion and use AWK.) Why write a program in a language you don't
know well when tools are already available to do the job.
If there is no absolutely compelling reason to do this in C++, you are using the wrong programming language for this. In awk, your whole program is:
{ if ( FNR % 4 == 1 ) print; }
Or, giving the whole command line e.g. in sh to filter lines 1,5,9,13,...:
awk '{ if ( FNR % 4 == 1 ) print; }' a.txt > b.txt