In C++, Ubunt 12.04, I have a file named config.txt which contains user name and password. I have 2 public static string variables: USER and PASSWORD. This is my code:
// Read file from config
string text[2];
int count = 0;
while(!fin.eof()){
getline(fin,text[count]);
count++;
if(count == 2){
break;
}
}
CONNECTOR::USER = text[0];
CONNECTOR::PASSWORD = text[1];
string userAndPassword = CONNECTOR::USER + ":" + CONNECTOR::PASSWORD;
cout << CONNECTOR::USER << endl; // It's fine, right user: qsleader
cout << CONNECTOR::PASSWORD << endl; // ok, right password: 123456
cout <<"user and password: " << userAndPassword << endl; // It's weird text! Problem here!
The weird text result is: :123456d password: qsleader!! This is not what I expected! But I don't know why this happen? Can anyone give me an suggestion? (If i print: cout << "user and password: qsleader:123456", the result is good!!)!
The problem is created when you read the values. Indeed, I guess that your file has the two items on two different lines. Furthermore, I guess this file uses Windows line endings. Therefore, when you read the first item, it reads qsleader\r and then stops as the next extracted character is \n, extracted but not appended to the string.
When you create the userAndPassword string, it is in fact qsleader\r:123456. This special character \r is a return carriage. It makes the cursor go to the beginning of the line. Therefore, on the last line, you first output user and password: qsleader, then go back to the first column, and write :123456, resulting in :123456d password: qsleader.
You are setting userAndPassword to a hellish expression involving assignments. I guess your intent was:
string userAndPassword = CONNECTOR::USER + ":" + CONNECTOR::PASSWORD
Related
I am relatively new to programming and this project is one of the very first projects that I am doing in my own time.
I am basically trying to make a login registration program that hashes user-entered data and stores it in a text file. The login option basically accesses that text file and compares it with the user entered data to see if there exists any such username and password combinations. The registration option basically writes the user data into the file. I am not very far into the project since I want to add a few more "features" to the program so it works a bit better. Currently, however, I encountered a slight problem while reading the data from the text file for the login option. Basically, one of the hashed passwords stored in the text file contains \x1a as a part of its hash. I think the program always ends whenever it reads this sub-control character since it reaches the end of the file. What I want to know is how to avoid a hash that has such a character.
I am using the crypto++ library (I am not too familiar with it).
The hash function:
void hashingFunc(string originalPass, string& hashedPass) {
using namespace CryptoPP;
SHA3_256 hash;
hash.Update((const byte*)originalPass.data(), originalPass.size());
encryptedPass.resize(hash.DigestSize());
hash.Final((byte*)&encryptedPass[0]);
}
The read function:
void readFileFunc(fstream& outputFile, const string FILE_NAME, string userNameHash, string passWordHash) {
string localUserHash;
string localPassHash;
if (!outputFile) {
cout << "File containing login information failed to open. Please try again." << endl;
cout << "If the problem persists, check file name and location." << endl;
cout << "File Name in the system: " << FILE_NAME << endl;
}
else {
while (outputFile) {
if (outputFile.eof())
break;
getline(outputFile, localUserHash);
getline(outputFile, localPassHash);
if (localUserHash == userNameHash) {
if (localPassHash == passWordHash) {
cout << "Successful Login!" << endl;
}
}
}
}
}
Here I have a file that reading in to a vector
typedef struct contacts
{
string name; //{jhonathan , anderson , felicia}
string nickName; //{jhonny , andy , felic}
string phoneNumber; // {13453514 ,148039 , 328490}
string carrier; // {atandt , coolmobiles , atandt }
string address; // {1bcd , gfhs ,jhtd }
} contactDetails;
vector <contactDetails> proContactFile;
I want to let user to delete a contact record from the file.For this I wrote a code.But from the code that i've written it deletes all the contact details from the file.But what I want here is when a user types a name then the program should delete only the name and the relevent nickname,carrier,phone number and address belongs to that name.Here is the code that i've written
string readString, selectContact;
cout << "Enter the name you want to delete" << endl;
cin >> selectContact;
ifstream fin;
fin.open(contactsFile);
if (!fin.is_open())
{
cout << "Unable to open Contacts.csv, please make sure file exists!" << endl;
}
ofstream fout;
fout.open("temp.csv" , ios::out);
while (getline(fin, readString))
{
if (((readString = readString.find(selectContact), 0)) == 0)
{
fout << readString <<',' << "\n";
}
cout << "Deleted Successfully" << endl;
showTableContacts();
}
if (((readString = readString.find(selectContact), 0) != 0))
{
cout << "\n" << selectContact << " not found" << endl;
}
fout.close();
fin.close();
remove("Contact.csv");//Deletes contacts.csv file
rename("temp.csv" , "Contact.csv");//Rename temp file as Contacts.csv
}
if (((readString = readString.find(selectContact), 0)) == 0)
This line has several issues.
readString.find(selectContact) returns the index of the match, or string::npos if it's not found. Checking that it is an exact match at position 0 is ok, technically, however, in your case if your string is "abcdefg" and you search for "abc" it will also match at position 0 when it shouldn't. You need to ensure the entire field matches, not just the first characters of it. (Find the first ',' in your line then ensure that all the bytes from the beginning up to the comma match your contact.)
Next consider this part:
readString = readString.find(selectContact)
You are assigning the result of the find to your string. That is, if find() returns 3, you will assign 3 to your string, which is interpreted as an ASCII character, and now your readString contains a single byte with junk in it. (In ASCII, 'A' is 65, etc)
So now your string is obliterated, and the index of your match is the contents, in the first byte (if the value is in range, or undefined behavior if it overflows.)
Code of this form:
if (xxx, 0)
is utilizing the comma operator, which sequences expressions by evaluating them from left to right, applying side effects (but throwing away the results) and the full expression evaluates to the value of the rightmost expression. Whatever xxx does (in your case, xxx is the code in step 2 above, obliterating your string) its return value is discarded and this whole expression evaluates to 0, which converts to a bool as false. Every time. (1,2,3) evaluates to 3, etc.
Therefore:
(readString = readString.find(selectContact), 0)
always evaluates to 0. And
if (((readString = readString.find(selectContact), 0)) == 0)
always obliterates your string, then tests if 0==0 which is always true.
Also, you almost never want to delete your input files. Rewriting them is dangerous enough, but you must be absolutely sure that everything succeeded before doing so; otherwise your program can end up causing a lot of pain if it deletes the input file and nothing else.
This is a part of my code. I don't know why the string was partially overwrite by another string.
for(int xd = 0 ; xd < 10; xd++)
{
if(booklist[xd].length() != 0)
{
string d = string(booklist[xd]);
string e = "1,2,3,4";
string f = d + e;
cout << d.length() << endl;
cout << d << endl;
cout << f.length() << endl;
cout << f << endl;
}
}
The result of this code is:
16
brave new world
23
1,2,3,4ew world
28
nineteen eighty-four (1984)
35
1,2,3,4n eighty-four (1984)
I don't know why i got this wrong result.
Could someone help me?
Are you populating booklist by pulling from a file that you copied from Windows to a linux machine?
Windows will add a carriage return '\r' to the end of each line in addition to a newline. If you're reading from a windows file and using getline, it'll pull the carriage return into the string.
When a carriage return is output in the terminal, it resets the cursor to the beginning of the line, which would result in the behavior you're seeing.
To fix this, see this question on trimming whitespace from a string. The function you're looking for from that answer is rtrim (or "right trim"):
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
It's likely that your booklist entries have trailing carriage returns, causing line 4 (for instance) to print brave new world, return to column 1, and print 1,2,3,4 over it. (That's why the character count is greater on line 3 than line 1, despite the two lines having the same apparent length.)
Strip the trailing whitespace from booklist entries (or figure out why it's getting in there in the first place, and deal with that) and things should be fine.
Yes i got the reason why it shows wrong.
Just like what scohe001 said: when i use getline to put the file in to an array, it will add \r after each element, so i use substr to remove the \r .Now it get work. Thanks every one.
Using fstreams I have a file opened that contains numerous lines. Each contiguos set of 4 lines are such that: the first line is an int, the second and third are strings and fourth is a double. This sequence continues till EOF.
I'm attempting to load these lines into a struct array:
struct Library {
int id;
string title;
string artist;
double price;
};
and the code I'm trying to implement to load data into the struct is this:
const int LIMIT = 10
Library database[LIMIT];
ifstream file;
file.open("list.txt");
if(file) {
while(!(file.eof()) && counter < LIMIT) {
file >> database[counter].id;
getline(file, database[counter].title;
getline(file, database[counter].artist;
file >> database[counter].price;
}
} else {
...
}
// Using the following to debug output
for(int i = 0; i < counter; i++) {
cout << "ID: " << database[i].id << endl
<< "Title: " << database[i].title << endl
<< "Artist: " << database[i].artist << endl
<< "Price: " << database[i].price << endl
<< "-----------------------" << endl;
}
The file I'm trying to throw at this thing is
1234
Never Gonna Give You Up
Rick Astley
4.5
42
Thriller
Michael Jackson
32.1
The problem I'm having here is that between reading the id and title using file >> ... and getline(...) is that somewhere a newline bite is being introduced screwing up the output, which displays this monstrosity...
ID: 1234
Title:
Artist: Never Gonna Give You Up
Price: 0
--------------------
ID: 0
Title:
Artist:
Price: 0
--------------------
The solution is probably the most basic of solutions, but mainly because I can't figure out exactly what is going on with the newline bite I can't combobulate a phrase to shove into google and do my stuff there, and I'm at the stage where I've been looking at a problem so long, basic knowledge isn't working properly - such as how to handle basic input streams.
Any form of help would be much appreciated! Thanks in advance :)
This happens because the >> operator for the input stream only grabs part of a line, and does not always grab the newline character at the end of the line. When followed by a call to getline, the getline will grab the rest of the line previously parsed, not the line after it. There are a few ways to solve this: you can clear the buffer from the input stream after each read, or you can simply get all your input from getline and just parse the resulting strings into an integer or a double when you need to with calls to stoi or stod.
As a side note, you don't want to detect the end of your file the way you presently are. See why is eof considered wrong inside a loop condition?
You can solve this problem by adding:
fflush(file);
everytime before you use getline(file, ...). Basically this will clear the input buffer before you use the getline() function. And fflush() is declared in the cstdio library.
file >> database[counter].id;
will read, in this case, a whitespace separated sequence of characters that is interpreted as an int. The newline is considered whitespace. You should now be sitting on that newline character, thus the getline() will read nothing -- successfully -- and increment the file position just past that.
You may be better off using getline() for each line and then separately interpreting the lines from the reading. For example, the first line read could be interpreted with a subsequent std::stoi() to get the integer representation from the string.
The cout statement in this for loop:
for (vector<Student>::iterator qw = students.begin(); qw != students.end(); ++qw){
Student a = *qw;
name = a.getName();
regno = a.getRegNo();
std::cout << "Name: "<< name << " Reg Number: " << regno << endl;
}
Is creating some odd behavior, what the cout should print is something like this:
Name: Mike Sanderson Reg Number: 10101
However which it actually prints out it:
Reg Number: 10101on
It would seem to me that after the second part of the cout statement it is going back to the start of the line and overwriting itself, but why?
Hope you guys can help me and if you need more info let me know!
This is what the carriage return character does (that is, \r in a string literal). I assume name string has an \r at the end of it. You'll need to figure out how it got there and remove it.
I'm guessing that perhaps you read the names from a file, and that file was created on Windows, which ends lines with \r\n by default. C++ will usually handle the conversion between line endings for you when reading from a text file, but if you're reading the file as a binary file and using \n as a delimiter, you'll have this problem. The \r will be read as though it were part of the line.