I have some weird issues I cannot figure out. When I run the code below which takes a file.txt reads it line by line into a vector<string> and then compares each index to string "--" it does not make it to the comparison stage.
Further more, in the convert_file() under the for loop string m, has some weird behavior: string m = "1"; m+= "--"; ('--' inside vector) m+= "2"; will print to console 2--; which makes me think something is bugging out the vector. The 2 is replacing the 1, the first character. This makes it look like the vector is bugged.
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
vector<string> get_file(const char* file){
int SIZE=256, ln=0;
char str[SIZE];
vector<string> strs;
ifstream in(file, ios::in);
if(!in){
return strs;
} else {
while(in.getline(str,SIZE)){
strs.push_back(string(str));
ln++;
}
}
in.close();
return strs;
}
void convert_file(const char* file){
vector<string> s = get_file(file);
vector<string> d;
int a, b;
bool t = false;
string comp = "--";
for(int i=0; i<s.size(); i++){
string m = "1";
m+= string(s.at(i));
m+= "2";
cout << m << endl;
if(s.at(i) == comp){
cout << "s[i] == '--'" << endl;
}
}
}
int main(){
convert_file("test.txt");
return 0;
}
now when I run a test file to check a similar program:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
vector<string> s;
s.push_back("--");
s.push_back("a");
for(int i=0; i<s.size(); i++){
cout << "1" << s.at(i) << "2" << endl;
if(s.at(i) == "--"){
cout << i << "= --" << endl;
}
}
return 0;
}
prints off 1--2, 0= --, 1a2. it works, it prints properly, and does the comparison. This leads me to think something is happening when I pull the line into a string.
Windows 7, cygwin64
g++ version 4.9.3
compile: D:\projects\test>g++ -o a -std=c++11 test.cpp
Based on the behavior and the discussion the lines in the file are terminated using a "\r\n" sequence. The easiest approach for dealing with the remaining '\r' is to remove it after reading a line. For example:
for (std::string line; std::getline(file, line); ) {
if (!line.empty() && line.back() == '\r') {
line.resize(line.size() - 1u);
}
strs.push_back(line);
}
If you insist in reading into char arrays you can use file.gcount() to determine the number of characters read to find the end of the string quickly. Note, however, that the number includes the bewline character, i.e., you'd want to check str[file.gcount() - 2] and potentially set it to '\0' (if the count is bigger or equal to 2, of course).
As answered by Dietmar Kühl already, the problem is with the \r\n line endings.
However, you should not need to modify your source code. The default behaviour in C++ is supposed to be to open files in text mode. Text mode means that whenever a line ending is found, where "line ending" depends on the platform you're using, it gets translated so that your program just sees a single \n. You're supposed to explicitly request "binary mode" from your program to disable this line ending translation. This has been long-standing practise on Windows systems, is the behaviour well supported by the C++ standard, and is the expected behaviour with native Windows compilers, but for compatibility with POSIX and existing Unix programs that do not bother setting the file mode properly, Cygwin ignores this and defaults to opening files in binary mode unless a custom Cygwin-specific text mode is explicitly requested.
This is covered in the Cygwin FAQ. The first solutions provided there (using O_TEXT or "t", depending on how you open your file) are non-standard so break your code with other environments, and they are not as easy to use with C++ <fstream> file access.
However, the next solutions provided there do work even for C++ programs:
You can also avoid to change the source code at all by linking an additional object file to your executable. Cygwin provides various object files in the /usr/lib directory which, when linked to an executable, changes the default open modes of any file opened within the executed process itself. The files are
binmode.o - Open all files in binary mode.
textmode.o - Open all files in text mode.
textreadmode.o - Open all files opened for reading in text mode.
automode.o - Open all files opened for reading in text mode,
all files opened for writing in binary mode.
And indeed, changing your compiler and linker invocation from g++ -o a -std=c++11 test.cpp to g++ -o a -std=c++11 test.cpp /usr/lib/textmode.o, your program works without changes to your source code. Linking with textmode.o basically means that your I/O will work the way it already should work by default.
Related
Write a program that takes in a line of text as input, and outputs that line of text in reverse. The program repeats, ending when the user enters "Quit", "quit", or "q" for the line of text.
Ex: If the input is:
Hello
there
Hey
quit
Then the output is:
ereht
olleH
yeH
I tried this, but for some reason, it is giving me a new line in when a print the code and I do not know how to fix it, please help.
#include <iostream>
#include <string>
using namespace std;
int main() {
string userInput;
while (true)
{
string check = userInput;
if (check =="quit" || check == "Quit" || check =="q") {
break;
}
string reverse = "";
for (int i = userInput.length() - 1; i >= 0; i--) {
reverse = reverse + userInput.at(i);
}
cout << reverse << endl;
cin >> userInput;
}
return 0;
}
Your input statement
cin >> userInput;
happens only at the end of your main. Try moving it at the start of your main.
Read this C++ reference website. Consider reading the C++11 standard n3337.
Read first some good C++ programming book, the documentation of your C++ compiler (e.g. GCC, invoked as g++ -Wall -Wextra -g), and the documentation of your debugger (e.g. GDB).
Take inspiration from existing open source C++ software
such as Qt, RefPerSys, GCC, the Clang static analyzer (which should be helpful), Fish, FLTK etc.... and many others on github or gitlab.
Read more about std::string and std::cin
I'm trying to write a very simple program that reads its standard input line by line (until "end" appears at the beginning of a line). At the same time, it tries to construct a new string that contains the concatenation of all the lines.
The behavior is quite puzzling. The lines are correctly read (as shown by the cout << current << endl line). However, the constructed string isn't what I expect. Instead, it contains only the last read. However, if I replace construct.append(current) by construct.append("foo"), it works perfectly fine.
What am I doing wrong here?
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
int main() {
string construct;
while(true) {
string current;
getline(cin, current);
assert(!cin.eof());
if (current.find("end") == 0) { break; }
cout << current << endl;
construct.append(current);
}
cout << construct << endl;
return 0;
}
Compiled with:
g++ -o main main.cpp -Wall -std=c++0x
Input: input.txt
abcdef
ghij
end
Output: ./main < input.txt
abcdef
ghij
ghijef
If I type the input instead of using a file, it works as expected. Also I get the same result with gcc (linux) and clang (mac os).
I found the problem. My input file was an ascii file with CRLF line terminators (and I'm using a mac). The construct variable was created correctly, but it wasn't displayed properly by the terminal.
I copied the contents of my .txt file over to Word and deleted all of the hard returns, which worked, but that is not always ideal or possible. The character encoding did not seem to have an impact. What solved it is when I appended a line break as well as the string.
Text::Text(string file) {
ifstream in;
string line;
in.open( file.c_str() ); // because the file name is a parameter decided at runtime in my code
while(getline(in,line,'\n')){
fileContents.append(line+"\n"); // fixed by adding "\n" here
}
cout << "\n Final product:\n";
cout << fileContents;
}
I want to access specific lines in of text file to display or modify that one. My text file contains lines of different lengths and i heard cannot use seekg or seekp for such files. I got a code but it doesn't works. Can someone please tell me its fault of some other helpful idea?
#include <fstream>
#include <limits>
#include <string>
#include <iostream>
std::fstream& GotoLine(std::fstream& file, unsigned int num)
{
file.seekg(std::ios::beg);
for(unsigned int i=0; i < num - 1; ++i)
{
file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
return file;
}
int main()
{
using namespace std;
std::fstream& GotoLine(std::fstream& file, unsigned int num);
cout << "Starting..." << endl;
fstream file("bla.txt");
GotoLine(file, 8);
string line8;
file >> line8;
cout << "[" << line8 << "]" << endl;
// cin.get();
cout << "Finished..." << endl;
return 0;
}
string line8;
file >> line8;
will only extract until the first whitespace character is hit.
you could use something like:
string line8;
getline(file, line8);
This at least worked for me with the rest of your code on Windows 7 with VS2012
Standard C++11 (and earlier versions of the standard) dont have notion of lines contained inside files. Also POSIX (and even Windows or MacOSX) don't have it. Textual files usually contain lines of variable length (and only the line terminator is relevant, either \n or \r\n or \n\r, depending upon the operating system and perhaps the file read mode -binary or textual-).
In the 1960s or 1970s IBM mainframe OS/360 operating systems had "file" systems which did have files made of fixed-length lines, mimicking punched cards.
So, you have to read your file line by line and remember where are the line limits (or use std::istream::ignore to skip till \n).
Alternatively, read every line of your file into a std::vector<std::string> using std::getline on std::ifstream-s.
For /etc/fstab (or /proc/mounts) reading all the lines in a vector is a good idea, since it is always a tiny file. It usually have less than an few dozens of lines, often less than about a hundred char each. The pathological case could be a file with many thousand lines of comments, but that don't really happen in practice.
I'm coding a task monitoring, which updates tasks' progress using cout. I'd like to display one task progress per line, therefore I have to rollback several lines of the console.
I insist on "several" because \b does the job for one line, but does not erase \n between lines.
I tried std::cout.seekp(std::cout.tellp() - str.length()); but tellp() returns -1 (failure).
You can do cout << '\r'; to jump to the beginning of the current line, but moving upwards is system-specific. For Unix, see man termcap and man terminfo (and search for cursor_up). On ANSI-compatible terminals (such as most modern terminals available on Unix), this works to move up: cout << "\e[A";.
Don't try seeking in cout, it's unseekable most of the time (except when redirected to a file).
As mentioned in other answers, using the ncurses (or slang) library provides a good abstraction for terminal I/O on Unix.
Instead of filling with spaces (which is error-prone, because not every terminal is 80 characters wide), you can do \r + clr_eol: std::cout << "\r\e[K" << std::flush.
Use an output formatting library such as ncurses if you can; this simplifies terminal manipulation significantly.
Neither C nor C++ define anything like that. You need explicit terminal manipulation. On Unix you can use curses. Have no idea what's there for Windows.
I know this is an old post, but the accepted doesn't cover cases where cout is piped to a program or file and this is the top of my google searches. The following will handle both piped and non-piped stdout with slightly different behavior.
#include <iostream>
#include <functional>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define _isatty isatty
#define _fileno fileno
#endif
const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ?
[](const size_t& i) {
std::cout << "\rNumber " << i << std::flush;
} :
[](const size_t& i) {
static std::ios::off_type last(-1);
if(last != -1)
std::cout.seekp(last, std::ios::beg);
last = std::cout.tellp();
std::cout << "Number " << i << std::endl;
}
);
This is untested on windows, but should work. What it does is detect if the file descriptor or is a tty. If it is then it just writes '\r' if the pos hasn't changed since last time it printed or a newline. If it isn't a newline, it seeks to the last place it was after it printed.
It behaves differently for files than for tty. For a file, if something outputs to the stream between prints then it can overwrite some or all of what was written even after newlines. For ttys it just overwrites the chars at the beginning of the current line.
You can use first system(" "); for you can use \e[A (Dev-C++) or \u001B[A (Visual Studio)
#include <iostream>
using namespace std;
int main()
{
system(" ");
string Input;
do
{
cout << "[#][\e[s";
cin >> Input;
cout << "[\e[u" << Input << "]"<<endl;
} while (2==2);
return 0;
}
enter image description here
Hope it helps ;) [It should work on Linux.]
// "\e[0K" Clear line from cursor to the end
cout << "\e[A\r\e[0K"<<what_you_want<<endl;
Output from debug:
File opened...
File contents:
Output from .exe (run via double click from /project/debug):
File opened...
File contents:
line1
line2
etc. . .
Source code:
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
using namespace std;
using namespace tr1;
int main()
{
string line;
list<string> dataList;
ifstream myFile("test_data.txt");
if (! myFile)
{
cout << "Error opening file. \n";
return 0;
}
else
{
cout << "File opened... \n";
while( getline(myFile, line) ) {
dataList.push_back(line);
}
}
cout << "\n\n File contents:";
list<string>::iterator Iterator;
for(Iterator = dataList.begin();
Iterator != dataList.end();
Iterator++)
{
cout << "\t" + *Iterator + "\n";
}
getchar();
return 1;
}
thank you for your help!
i now understand the problem, thank you. obviously, this also shows that this method of error handling for files is worthless. I have corrected that as well. Thanks again.
The way you've coded this line:
ifstream myFile("test_data.txt");
means that the code is looking for the file in the current working directory.
When you run outside the debugger that will be /project/debug (in your case), which is where the file presumably is.
When you run inside the debugger that will (probably) be \project, which won't contain the file.
You'll need to either have two copies of the file, hard code the full path to the file, or have some way of specifying the file at runtime.
You can also specify the working directory (where it will look for test_data.txt) in the Debug property page for your project in VC.
Your .exe is normally run from Debug/../ when started from Visual Studio. When you double-click on it, it runs in 'Debug/'.
Either move your test_data.txt, or do as most developers and create an output directory where your binaries and data are exported before run.