Converting C function to C++ language - c++

Since this is my first encounter with the C programming language, it's not clear to me how I'm going to convert a piece of code to C++. I know that this code can be used in C ++ but I want to work exclusively on the syntax of the C++ language.
Here is my code:
FILE *f;
char name[10],surname[10],j[10];
f=fopen("Marks.txt","r");
fscanf(f,"%d",&n);
I want to open the file using:
ifstream input;
input.open("Marks.txt");
But then I don't know what to use instead of the fscanf function because I can no longer use FILE *f;

Like this:
int main()
{
// Let the constructor handle opening the file.
std::ifstream input("Marks.txt");
int n = 0;
std::string s;
double d = 0;
// Read an int, followed by a string, followed by a double.
if (input >> n >> s >> d)
{
std::cout << "Success!\n";
}
else
{
std::cout << "Failure!\n";
}
// The destruction of 'input' will close the file.
}

Here's the C++ way to do it, though you technically can still use that C code.
#include <ifstream>
int main() {
std::string str;
int i;
double d;
char c_str[10];
std::ifstream input;
input.open("Marks.txt");
input >> str; // reads a word of text into str
input >> i; // assuming there is a valid integer after the first line, reads it into i
input >> d; // assuming there is a valid double after that, reads it into d
// reads up to 9 characters + a '\0', stopping if it reaches a period
input.get(c_str, 10-1, '.');
// etc.
}

First to do is make a std::fstream object then open the file of your choice, you can do any lines (in sequence) of the following:
// Option 1
std::fstream input; // create the object
input.open("Marks.txt", ios::in); // since this is a `std::fstream` object, you'll need to specify `ios::in` for input operations
// Option 2
std::ifstream input; // create the object, this time dedicated to input
input.open("Marks.txt"); // no need to specify `ios::in`
// Option 3
std::fstream input("Marks.txt", ios::in); // you can directly open the file using the constructor, but specify `ios::in`
// Option 4
std::ifstream input("Marks.txt"); // directly opening the file using the constructor with the object dedicated to input
Next, you'll use operator>> or std::getline() to get input from the stream
// first declare the variables
std::string str1 = ""; // use std::string in C++ instead C-style strings (char[])
int ing1 = 0;
// Option 1
input >> str1; // this parses the contents of the file into str1, until the space
/*
Suppose "Marks.txt" has this inside it:
Hello World
The first content of the file until a space is "Hello", this string parsed into str1
*/
// Option 2
ing1 = input.get() // this parses only one character then turns it into an integer (destination type) into ing1
/*
Suppose "Marks.txt" has this inside it:
1234567890
ing1 will bear the value 1.
however, like std::iostream, this does not convert the character to it's integral value (ASCII, automatically) thus when:
abcdefghij
ing1 will have the value 0, since 'a' is not an integer
*/
// Option 3
input.getline(str1, 6); // this will parse into str1 six (6) characters, including spaces (not sure with control characters)
/*
Suppose "Marks.txt" has this inside it:
StackOverflow
"StackO" will be parsed into str1
*/
Note: this operations differ when stream is opened in binary mode (ios::binary) and be careful with std::getline() this may overload the buffer (especially when specified with std::numeric_limits<std::streamsize>::max())
EDIT: IMPORTANT close the stream after using.
// some operations here
// file is no longer needed -> close it
input.close();

Related

how to make a new line in binary file c++?

Can anybody help me with this simple thing in file handling?
This is my code:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
fstream f;
f.open("input05.bin", ios_base::binary | ios_base::out);
string str = "";
cout << "Input text:"<<endl;
while (1)
{
getline(cin, str);
if (str == "end")
break;
else {
f.write((char*)&str, sizeof(str));
}
}
f.close();
f.open("input05.bin", ios_base::in | ios_base::binary);
while (!f.eof())
{
string st;
f.read((char*)&st, sizeof(st));
cout << st << endl;
}
f.close();
}
It is running successfully now. I want to format the output of the text file according to my way.
I have:
hi this is first program i writer this is an experiment
How can I make my output file look like the following:
hi this is first program
I writer this is an experiment
What should I do to format the output in that way?
First of all,
string str;
....
f.write((char*)&str, sizeof(str));
is absolutely wrong as you cast a pointer to an object of type std::string to a pointer to a character, i.e. char*. Note that an std::string is an object having data members like the length of the string and a pointer to the memory where the string content is kept, but it is not a c-string of type char *. Further, sizeof(str) gives you the size of the "wrapper object" with the length member and the pointer, but it does not give you the length of the string.
So it should be something like this:
f.write(str.c_str(), str.length());
Another thing is the os-dependant handling of new line character. Depending on the operating system, a new line is represented either by 0x0d 0x0a or just by 0x0d. In memory, c++ treats a new line always as a single character '\n'(i.e. 0x0d). When writing to a file in text mode, c++ will expand an '\n' to 0x0d 0x0a or just keep it as 0x0d (depending on the platform). If you write to a file in binary mode, however, this replacement will not occur. So if you create a file in binary mode and insert only a 0x0d, then - depending on the platform - printing the file in the console will not result in a new line.
Try to write ...
f.write(str.c_str(), str.length());
f.put('\r');
such that it will work on your platform (and will not work on other platforms then).
That's why you should write in text mode if you want to write text.

How can I convert a char array to a string in C++?

I have a char array called firstFileStream[50], which is being written to from an infile using fstream.
I want to convert this char array into a string called firstFileAsString. If I write string firstFileAsString = firstFileStream; it only writes the first word within the array and stops at the first space, or empty character. If I write firstFileAsString(firstFileStream) I get the same output.
How do I write the whole char array, so all words within it, to a string?
Here is the code to read in and write:
string firstInputFile = "inputText1.txt";
char firstFileStream[50];
ifstream openFileStream;
openFileStream.open(firstInputFile);
if (strlen(firstFileStream) == 0) { // If the array is empty
cout << "First File Stream: " << endl;
while (openFileStream.good()) { // While we haven't reached the end of the file
openFileStream >> firstFileStream;
}
string firstFileAsString = firstFileStream;
}
My problem, as zdan pointed out, is I was only reading the first word of the file, so instead I've used istreambuf_iterator<char> to assign the content directly to the string rather than the character array first. This can then be broken down into a character array, rather than the other way around.
openFileStream >> firstFileStream;
reads only one word from the file.
A simple example of reading the whole file (at least up to the buffering capacity) looks like this:
openFileStream.read(firstFileStream, sizeof(firstFileStream) - 1);
// sizeof(firstFileStream) - 1 so we have space for the string terminator
int bytesread;
if (openFileStream.eof()) // read whole file
{
bytesread = openFileStream.gcount(); // read whatever gcount returns
}
else if (openFileStream) // no error. stopped reading before buffer overflow or end of file
{
bytesread = sizeof(firstFileStream) - 1; //read full buffer
}
else // file read error
{
// handle file error here. Maybe gcount, maybe return.
}
firstFileStream[bytesread] = '\0'; // null terminate string

Why is the c++ input file stream checked twice here?

Here is a snippet from a c++ tutorial:
// istream::get example
#include <iostream> // std::cin, std::cout
#include <fstream> // std::ifstream
int main () {
char str[256];
std::cout << "Enter the name of an existing text file: ";
std::cin.get (str,256); // get c-string
std::ifstream is(str); // open file
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
if (is.good())
std::cout << c;
}
is.close(); // close file
return 0;
}
Notice is.good() appeared twice, first with while, then with if.
Link to the example: http://www.cplusplus.com/reference/istream/istream/get/
Why is the c++ input file stream checked twice here?
The fact of the matter is that it is unnecessarily checked twice. If the second inner if (is.good()) passes, then the outer while (is.good()) will always pass as well. The author of the code needed some way of looping, and he incorrectly assumed that a while (is.good()) is an appropriate condition because it will stop the loop when the stream fails to extract. But this is only half-true. while (is.good()) is never the correct way to perform the extraction.
You have to perform the input first and then check if it succeeded. Otherwise it is possible to perform a failed extraction, use the result of that extraction and receive unwanted behavior from your program. The correct way to do it is by using the extraction itself as the condition. The input operator will return a reference to the stream, and then it will turn into a boolean returning true if the previous read suceeded, or false otherwise:
while (is.get(c))
{
std::cout << c;
}
The variable c is also not outside of the loop. You can enclose the while() loop in a block or use a for() loop instead:
for (char c; is.get(c); )
{
std::cout << c;
}
But it seems that this code is attempting to write all the content from the file to standard output. Reading a character one-by-one is the way shown here, but you can also use stream iterators or the buffer overload of std::ostream::operator<<() as well.
There are two more problems I see in this code. Namely:
std::string is the preferred construct for manipulating dynamically-sized strings, not C-style strings which require the use of archaic input methods such as .get(), .getline(), etc, and their respective overloads.
Manually closing a file is usually unneeded. The stream will close itself at the end of the scope in which it was created. You probably only want to close the file yourself to check if it succeeds or to reopen the stream with a different file or openmode.
The first one, that in while (is.good()), checks if it has reached EOF (End Of File). If not, it doesn't enter the while loop. Once entered in while(), it means that it have at least one character remained for the instruction char c = is.get();.
What the second if() does is that it doesn't allow to print the last character read, because after a char c = is.get();, the file may reach EOF. In case it does, the character is not printed.
For example, let's say you have this file:
"Just an example!"
Now, if you had just:
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
std::cout << c;
}
the output would be: "Just an example! ". The last space is the EOF character (which is the last character read).
But with:
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
if (is.good())
std::cout << c;
}
the output would be: "Just an example!", which is what you would expect it to be.

C++ fstream - problems reading only certain variable types

I am using fstream to read a notepad file containing numerical data. I am using dynamic memory allocation and the data is type float.
However there is rouge data in form of characters in my file - how would I write code that searches for and ignores the characters in the file, and only reads in the numbers?
I am assuming I will need to use either ignore or peek?
fstream myfile("data1");
myfile.ignore ();
or myfile.peek ();
But am a bit unsure. Any help is appreciated!
If it has always this format, the words and numbers are separated by whitespace, you can simply read it one string at a time and let a std::istringstream do the parsing. When this fails, you know it is not a number
std::string word;
while (myfile >> word) {
std::istringstream is(word);
double d;
if (is >> d) {
// found a number
std::cout << d << '\n';
} else {
// something's wrong
std::cerr << word << '\n';
}
}
Update:
Due to popular demand: a stringstream works like any other stream (std::cin, std::cout or std::fstream). The main difference is that a stringstream operates on strings. This means input comes from a string instead of a file or standard input, or output goes to a string, much like it goes to standard output or a file.
Parsing input is like this typically requires that you extract the tokens into a string and
test the content of your string against your parsing requirements. For example, when you extract into the string, you can then run a function which inserts it into a std::stringstream, then extract into the data type you're testing against, and see if it succeeds.
Another option is to check if the string is not a certain string, and convert back to the desired data type if so:
while (f >> str)
{
if (f != "badInput")
{
// convert to double and add to array
}
}
Fortunately you can use the Boost.Regex facilities to avoid having to do most of the work yourself. Here's an example similar to yours:
#include <boost/regex.hpp>
int main()
{
std::fstream f("test.txt");
std::string token;
boost::regex floatingPoint("((\\+|-)?[0-9]+)?(\\.)?([0-9]+)");
while (f >> token)
{
if (boost::regex_match(token, floatingPoint))
{
// convert to double using lexical_cast<> and add to array
}
}
Thanks for the help everybody - But all this seems a bit advanced for someone of my poor capability! We have been suggested to use the following - but am unsure how you would do this to distinguish between words and numbers:
fstream myfile("data1");
myfile.eof ();
myfile.good ();
myfile.fail ();
myfile.clear ();
myfile.ignore ();
myfile.close ();
myfile.peek ();

Read a txt file into a multi variable dimension array in c++

I've the need of read a txt file that is structured in this way
0,2,P,B
1,3,K,W
4,6,N,B
etc.
Now I need to read in an array like arr[X][4]
The problem is that I don't know the number of lines inside this file.
In addition I'd need 2 integers and 2 char from it...
I think I can read it with this sample of code
ifstream f("file.txt");
while(f.good()) {
getline(f, bu[a], ',');
}
obviusly this only shows you what I think I can use....but I'm open to any advice
thx in advance and sry for my eng
Define a simple struct to represent a single line in the file and use a vector of those structs. Using a vector avoids having to manage dynamic allocation explicitly and will grow as required.
For example:
struct my_line
{
int first_number;
int second_number;
char first_char;
char second_char;
// Default copy constructor and assignment operator
// are correct.
};
std::vector<my_line> lines_from_file;
Read the lines in full and then split them as the posted code would allow 5 comma separated fields on a line for example, when only 4 is expected:
std::string line;
while (std::getline(f, line))
{
// Process 'line' and construct a new 'my_line' instance
// if 'line' was in a valid format.
struct my_line current_line;
// There are several options for reading formatted text:
// - std::sscanf()
// - boost::split()
// - istringstream
//
if (4 == std::sscanf(line.c_str(),
"%d,%d,%c,%c",
&current_line.first_number,
&current_line.second_number,
&current_line.first_char,
&current_line.second_char))
{
// Append.
lines_from_file.push_back(current_line);
}
}