I want to read the 3rd line from a text file in as a string, convert it to a long long int, and return that value.
The data on the 3rd line of the text file is 1234567890123456
long long int File::Getline3(int user1, int user3)
{
std::string filename = std::to_string(user1);
std::ifstream fin(filename + ".txt");
fin.getline (line1, 5);
fin.getline (line2, 5);
fin.getline (line3, 20);
fin.close();
// convert line 3 to a string called str
const char *line3;
std::string str(line3);
// convert str to long long int called user3
long long int strtoll(const char *nptr, char **endptr, int base);
char* endptr = NULL;
user3 = strtoll(str.c_str(), &endptr, 10);
return user3;
}
The comments are in to show what I think I'm doing, however I am probably wrong (I'm new to pointers).
I get an "unresolved external" error when I try to build my program.
long long int strtoll(const char *nptr, char **endptr, int base);
This line declares a function. It means that when you call strtoll a few lines down, you're going to be calling that function as it's the most obvious candidate. However, you never defined it.
Instead you meant to call std::strtoll, which is defined (by the standard library), and which will be found through your presumed using namespace std directive if you do not hide it by falsely declaring this non-existent function of your own with the same name. :)
Simply remove the excess declaration:
// convert str to long long int called user3
char* endptr = NULL;
user3 = strtoll(str.c_str(), &endptr, 10);
You have a similar issue with your const char* line3, which you declare inside the function, never assign anything to, then construct a string out of. That's undefined; the pointer is uninitialised. Assuming you have some line3 data member (along with your line1 and line2), again you're hiding it with a local variable of the same name.
Finally, passing user3 in by value is utterly pointless if you're just writing to it and returning it. Remove that parameter.
Putting all this together, your code should probably look like:
// convert line3 to long long int
char* endptr = NULL;
return strtoll(line3, &endptr, 10);
In short, be less declaration-happy!
https://connect.microsoft.com/VisualStudio/feedback/details/758053/missing-strtold-strtoll-strtoull-functions-from-stdlib-h
A work around for Visual C++ that does not have these included.
long long int File::Getline3(int user1)
{
std::string filename = std::to_string(user1);
std::ifstream fin(filename + ".txt");
std::string line1, line2; // place to actually store the lines
getline(fin, line1); // read a line
getline(fin, line2); // read another line
long long int number_on_line_3; // somewhere to store the number
fin >> number_on_line3; // store the number
fin.close();
return number_on_line_3; // return the number
}
Related
console
file
Simple explanation: ifstream's get() is reading the wrong chars (console is different from file) and I need to know why.
I am recording registers into a file as a char array. When I write it to the file, it writes successfully. I open the file and find the chars I intended, except notepad apparently shows unicode character 0000 ( NULL) as a space.
For instance, the entries
id = 1000; //an 8-byte long long
name = "stack"; //variable size
surname = "overflow"; //variable size
degree = "internet"; //variable size
sex = 'c'; //1-byte char
birthdate = 256; //4-byte int
become this on the file:
& èstackoverflowinternetc
or, putting the number of unicode characters that disappear when posted here between brackets:
&[3]| [1]è|stack|overflow|internet|c| [1] | //separating each section with a | for easier reading. Some unicode characters disappear when I post them here, but I assure you they are the correct ones
SIZE| ID | name| surname| degree |g| birth
(writing is working fine and puts the expected characters)
Trouble is, when the console in the code below prints what the buffer is reading from the file, it gives me the following record (extra spaces included)
Þstackoverflowinternetc
Which is bad because it returns me the wrong ID and birthdate. Either "-21" and "4747968" or "Ù" and "-1066252288". Other fields are unnaffected. Weird because size bytes show up as empty space in the console, so it shouldn't be able to split name, surname, degree and sex.
ifstream infile("alumni.freire", ios::binary);
if(infile.is_open()){
infile.seekg(pos, ios::beg);
int size;
size = infile.get();
char charreg[size];
charreg[0] = size;
//testing what buffer gives me
for(int i = 1; i < size; i++){
charreg[i] = infile.get();
cout << charreg[i];
}
}
What am I doing wrong?
EDIT: to explain better what I did:
I get the entries on the first "code" from user input and use them as parameters when creating a "reg" class I implemented. The reg class then does (adequatly, I've already tested it) the conversion to strings, and calculates a hidden four-element char array containing instance size, name size, surname size and degree size. When the program writes the class on-file, it is written perfectly, as I showed in the second "code" section. (If you do the calculations you'll see '&' equals the size of the entire thing, for example). When I read it from the file, it appears differently on console for some reason. Different characters. But it reads the right amount of characters because "name", "surname" and "degree" appear correctly.
EDIT n2: I made "charreg[]" into an int array and printed it and the values are correct. I have no idea what's happening anymore.
EDIT n3: Apparently the reason I was getting the wrong chars is that I should have used unsigned chars...
The idea to write, as is, your structure is good. But your approach is wrong.
You must have something to separate your fields.
For example you know that your ID is 8 byte long, great ! You can read 8 bytes :
long long id;
read(fd, &id, 8);
In your example you got -24 because you read the first byte of the full id number.
But for the rest of the file, how can you know the length of the first name and the last name ?
You could read byte by byte until you find an null byte.
But I suggest you to use a more structured file.
For example, you can define a structure like this :
long long id; // 8 bytes
char firstname[256]; // 256 bytes
char lastname[256]; // 256 bytes
char sex; // 1 byte
int birthdate; // 4 bytes
With this structure you can read and write super easily :
struct my_struct s;
read(fd, &s, sizeof(struct my_struct)); // read 8+256+256+1+4 bytes
s.birthdate = 128;
write(fd, &s, sizeof(struct my_struct));// write the structure
Of course you loose the "variable length" of the first name and last name. Do you really need more than 100 chars for a name ?
In a case you really need, you could introduce an header over each variable length value. But you loose the ability to read everything at once.
long long id;
int foo_size;
char *foo;
And then to read it :
struct my_struct s;
read(fd, &s, 12); // read the header, 8 + 4 bytes
char foo[s.foo_size];
read(fd, &s, s.foo_size);
You should define what exactly you need to save. Define a precise data structure that you can easily deduce at read, avoid things like "oh, let's read until null-byte".
I used C function to explain you because it's much more representative. You know what you read and what you write.
Start to play with this, and then try the same with c++ streams/function
I don't know how you are writing back information to the file but here is how I would do that, I'm hoping this is a fairly simple way of doing it. Keep in mind I have no idea what kind of file you are actually working with.
long long id = 1000;
std::string name = "name";
std::string surname = "overflow";
std::string degree = "internet";
unsigned char sex = 'c';
int birthdate = 256;
ofstream outfile("test.txt", ios::binary);
if (outfile.is_open())
{
const char* idBytes = static_cast<char*>(static_cast<void*>(&id));
const char* nameBytes = name.c_str();
const char* surnameBytes = surname.c_str();
const char* degreeBytes = degree.c_str();
const char* birthdateBytes = static_cast<char*>(static_cast<void*>(&birthdate));
outfile.write(idBytes, sizeof(id));
outfile.write(nameBytes, name.length());
outfile.write(surnameBytes, surname.length());
outfile.write(degreeBytes, degree.length());
outfile.put(sex);
outfile.write(birthdateBytes, sizeof(birthdate));
outfile.flush();
outfile.close();
}
and here is how I am going to output it, which to me seems to be coming out as expected.
ifstream infile("test.txt", std::ifstream::ate | ios::binary);
if (infile.is_open())
{
std::size_t fileSize = infile.tellg();
infile.seekg(0);
for (int i = 0; i < fileSize; i++)
{
char c = infile.get();
std::cout << c;
}
std::cout << std::endl;
}
I'm trying to read in a .csv file filled with floats. I used this to build my code. However, the data reads in correctly but is read in as a string but I want to use the data as floats. If I try to use stof(string) I get an error that it is trying to convert a non number to a number. So I went the really long way and converted the string to a char and that to a float, which works but is VERY ugly. However, once all the data is read in and is printed out with a cout the program my crashes
trackBarFile.open("test2.csv");
std::string line, line2, line3;
int count;
std::string token;
float tokenNum,lineFloat,line2Float,line3Float;
char cstr[5],cstr2[5];
while (getline(trackBarFile, line,','))
{
cstr[line.size()+1];
strcpy(cstr, line.c_str());
lineFloat = atof(cstr);
getline(trackBarFile, line2,',');
cstr[line2.size()+1];
strcpy(cstr, line2.c_str());
line2Float = atof(cstr);
getline(trackBarFile, line3);
cstr2[line3.size()+1];
strcpy(cstr2, line3.c_str());
line3Float = atof(cstr2);
std::cout<<line<<","<<lineFloat<<" , "<<line2<<","<<line2Float<<" , "<<line3<<","<<line3Float<<std::endl;
}
trackBarFile.close();
It seems I have stumbled upon the answer to my own question. Thanks to the above questions I started looking for different ways to convert the string to a float. The +2 in the print out can be ignored, was my "pinch" to make sure I wasn't dreaming
trackBarFile.open("TrackBarSignal.csv");
std::ofstream fout;
fout.open("Output_ReadInCSV.txt");
std::string line, line2, line3;
int count;
float tokenNum,lineFloat,line2Float,line3Float;
while (getline(trackBarFile, line,',')&&getline(trackBarFile, line2,',')&&getline(trackBarFile, line3))
{
lineFloat = (float)atof(line.c_str());
line2Float = (float)atof(line2.c_str());
line3Float = (float)atof(line3.c_str());
std::cout<<line<<","<<lineFloat+2<<" , "<<line2<<","<<line2Float+2<<" , "<<line3<<","<<line3Float+2<<std::endl;
}
trackBarFile.close();
Actually i have a requirement wherein i need to open the same file using wfstream file instance at one part of the code and open it using fstream instance at the other part of the code. I need to access a file where the username is of type std::wstring and password is of type std::string. how do i get the values of both the variables in the same part of the code?
Like you can see below i need to get the values for username and password from the file and assign it to variables.
type conversion cannot be done. Please do not give that solution.
......file.txt.......
username-amritha
password-rajeevan
the code is written as follows:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main()
{
std::string y;
unsigned int l;
std::wstring username;
std::wstring x=L"username";
std::wstring q;
std::string password;
std::string a="password";
std::cout<<"enter the username:";
std::wcin>>username;
std::cout<<"enter the password:";
std::cin>>password;
std::wfstream fpp("/home/aricent/Documents/testing.txt",std::ios::in | std::ios::out );
std::getline(fpp,q);
if (q.find(x, 0) != std::string::npos) {
std::wstring z=q.substr(q.find(L"-") + 1) ;
std::wcout<<"the username is:"<<z;
fpp.seekg( 0, std::ios::beg );
fpp<<q.replace(x.length()+1, z.length(), username);
}
fpp.close();
std::fstream fp("/home/aricent/Documents/testing.txt",std::ios::in | std::ios::out );
std::getline(fp,y);
if (y.find(a, 0) != std::string::npos)
{
unsigned int len=x.length()+1;
unsigned int leng=username.length();
l=len+leng;
fp.seekg(l+1);
std::string b=y.substr(y.find("-") + 1) ;
fp<<y.replace(a.length()+1, b.length(), password);
}
fp.close();
}
It's not recommended to open multiple streams to a same file simultaneously. On the other hand, if you don't write to the file, but only read (and thus, would be using ifstream and wifstream), that's probably safe.
Alternatively, you can simply open a wfstream, read the username, close the stream, open a fstream and read the password.
If you have the choice, avoid mixed encoding files entirely.
You should not try to open the same file with two descriptors. Even if it worked (read only mode for example), both descriptors would not be synchronised, so you would read first characters on one, and next same characters on second.
So IMHO, you should stick to one single solution. My advice is to use a character stream to process the file, and use a codecvt to convert from a narrow string to a wide wstring when you need it.
An example conversion function could be (ref: cplusplus.com: codecvt::in):
std::wstring wconv(const std::string& str, const std::locale mylocale) {
// define a codecvt facet for the locale
typedef std::codecvt<wchar_t,char,std::mbstate_t> facet_type;
const facet_type& myfacet = std::use_facet<facet_type>(mylocale);
// define a mbstate to use in codecvt::in
std::mbstate_t mystate = std::mbstate_t();
size_t l = str.length();
const char * ix = str.data(), *next; // narrow character pointers
wchar_t *wc, *wnext; // wide character pointers
// use a wide char array of same length than the narrow char array to convert
wc = new wchar_t[str.length() + 1];
// conversion call
facet_type::result result = myfacet.in(mystate, ix, ix + l,
next, wc, wc + l, wnext);
// should test for error conditions
*wnext = 0; // ensure the wide char array is properly null terminated
std::wstring wstr(wc); // store it in a wstring
delete[] wc; // destroy the char array
return wstr;
}
This code should test for abnormal conditions, and use try catch to be immune to exceptions but it is left as exercise for the reader :-)
A variant of the above using codecvt::out could be used to convert from wide string to narrow string.
In above code, I would use (assuming nconv is the function using codecvt::out to convert from wide string to narrow string):
...
#include <locale>
...
std::cin>>password;
std::locale mylocale;
std::fstream fp("/home/aricent/Documents/testing.txt",std::ios::in | std::ios::out );
std::getline(fp,y);
q = wconv(y, mylocale);
...
fp<<nconv(q.replace(x.length()+1, z.length(), username));
}
std::getline(fp, y);
...
I want to combine variable with string value in (ofstream) file path
Example:
long phNumber;
char bufPhNumber[20];
ofstream ifile;
cout << "Phone Number: ";
cin >> phNumber;
itoa(phNumber,bufPhNumber,20);
ifile.open("c://" + bufPhNumber + ".txt",ios::out); // error in this line
How to combine this variable (bufPhNumber) with that strings ( "c://" + variable here + ".txt" )
Do this:
ifile.open((std::string("c://") + bufPhNumber + ".txt").c_str(),ios::out);
Explanation :
It first creates a string, and concatenates the rest of c-strings using operator+() as:
std::string temp = std::string("c://") + bufPhNumber + ".txt";
then takes c_str() and pass this to .open():
ifile.open(temp.c_str(),ios::out);
However, in C++11, you don't need to do .c_str(), and you can use std::string directly.
A better solution should be this:
std::string phNumber; //declare it as std::string
cout << "Phone Number: ";
cin >> phNumber; //read as string
//use constructor
ofstream ifile(("c://" + phNumber + ".txt").c_str(), ios::out);
ofstream::open, at least before C++11 (a), requires a const char * for the file name, not a std::string, as per here.
Instead of:
ifile.open("c://" + bufPhNumber + ".txt",ios::out);
use the following:
string fspec = std::string ("c://") + bufPhNumber + ".txt";
ifile.open (fspec.c_str(), ios::out);
(and you may want to consider why your output file is called ifile).
(a) In C++11, there are two open functions for basic_ofstream:
void open(const char* s, ios_base::openmode mode = ios_base::out);
void open(const string& s, ios_base::openmode mode = ios_base::out);
so a string version would work there.
Okay, hi. You can't concatenate strings directly like in java, so your issue is here:
bufPhNumber + ".txt"
Given bufPhNumber is a char * and text is a char *, they don't support the + operator in the way that you intend.
There is strcat() for such a job, but it assumes the target string has enough room for the destination string, and it also modifies the target string.
char Array[28]; //One for the null
strcat(Array,"C:\\");
strcat(Array,bufPhNumber);
strcat(Array,".txt");
Although I recommend using a char array for phone numbers as long isn't very well suited for such storage as it can't hold as many digits as you like (you might consider using two ints/longs). Also, consider using unsigned long (as you don't get negative phone numbers). If you do use long/int, note that conversion from long to char array, and char array to long will take a chunk of memory and processing power, which on a bigger scale is less efficient than just using char arrays.
I'm parsing a string that follows a predictable pattern:
1 character
an integer (one or more digits)
1 colon
a string, whose length came from #2
For example:
s5:stuff
I can see easily how to parse this with PCRE or the like, but I'd rather stick to plain string ops for the sake of speed.
I know I'll need to do it in 2 steps because I can't allocate the destination string until I know its length. My problem is gracefully getting the offset for the start of said string. Some code:
unsigned start = 0;
char type = serialized[start++]; // get the type tag
int len = 0;
char* dest = NULL;
char format[20];
//...
switch (type) {
//...
case 's':
// Figure out the length of the target string...
sscanf(serialized + start, "%d", &len);
// <code type='graceful'>
// increment start by the STRING LENGTH of whatever %d was
// </code>
// Don't forget to skip over the colon...
++start;
// Build a format string which accounts for length...
sprintf(format, "%%%ds", len);
// Finally, grab the target string...
sscanf(serialized + start, format, string);
break;
//...
}
That code is roughly taken from what I have (which isn't complete because of the issue at hand) but it should get the point across. Maybe I'm taking the wrong approach entirely. What's the most graceful way to do this? The solution can either C or C++ (and I'd actually like to see the competing methods if there are enough responses).
You can use the %n conversion specifier, which doesn't consume any input - instead, it expects an int * parameter, and writes the number of characters consumed from the input into it:
int consumed;
sscanf(serialized + start, "%d%n", &len, &consumed);
start += consumed;
(But don't forget to check that sscanf() returned > 0!)
Use the %n format specifier to write the number of characters read so far to an integer argument.
Here's a C++ solution, it could be better, and is hard-coded specifically to deal with your example input, but shouldn't require much modification to get working.
std::stringstream ss;
char type;
unsigned length;
char dummy;
std::string value;
ss << "s5:Helloxxxxxxxxxxx";
ss >> type;
ss >> length;
ss >> dummy;
ss.width(length);
ss >> value;
std::cout << value << std::endl;
Disclaimer:
I'm a noob at C++.
You can probably just use atoi which will ignore the colon.
e.g. len = atoi(serialized + start);
The only thing with atoi is that if it returns zero it could mean either the conversion failed, or that the length was truly zero. So it's not always the most appropriate function.
if you replace you colon with a space scanf will stop on it and you can get the size malloc the size then run another scanf to get the rest of the string`
int main (int argc, const char * argv[]) {
char foo[20];
char *test;
scanf("%s",foo); //"hello world"
printf("foo = %s\n", foo);//prints hello
//get size
test = malloc(sizeof(char)* 10);//replace 10 with your string size
scanf("%s", test);
printf("test = %s\n", test);//prints world
return 0;
}
`
Seems like the format is overspecified... (using a variable length field to specify the length of a variable length field).
If you're using GCC, I'd suggest
if (sscanf(serialized,"%c%d:%as",&type,&len,&dest)<3) return -1;
/* use type, dest; ignore len */
free(dest);
return 0;