How to combine variable with string value - c++

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.

Related

Problems with file i/o using strings in c++ [duplicate]

Im having problems writing string into a binary file. This is my code:
ofstream outfile("myfile.txt", ofstream::binary);
std::string text = "Text";
outfile.write((char*) &text, sizeof (string));
outfile.close();
Then, I try to read it,
char* buffer = (char*) malloc(sizeof(string));
ifstream infile("myfile.txt", ifstream::binary);
infile.read(buffer, sizeof (prueba));
std::string* elem = (string*) buffer;
cout << *elem;
infile.close();
I just cant get it to work. I am sorry, I am just desperate. Thank you!
To write a std::string to a binary file, you need to save the string length first:
std::string str("whatever");
size_t size=str.size();
outfile.write(&size,sizeof(size));
outfile.write(&str[0],size);
To read it in, reverse the process, resizing the string first so you will have enough space:
std::string str;
size_t size;
infile.read(&size, sizeof(size));
str.resize(size);
infile.read(&str[0], size);
Because strings have a variable size, unless you put that size in the file you will not be able to retrieve it correctly. You could rely on the '\0' marker that is guaranteed to be at the end of a c-string or the equivalent string::c_str() call, but that is not a good idea because
you have to read in the string character by character checking for the null
a std::string can legitimately contain a null byte (although it really shouldn't because calls to c_str() are then confusing).
the line
outfile.write((char*) &text, sizeof (string));
is not correct
sizeof(string) doesn't return the length of the string, it returns the sizeof the string type in bytes.
also do not cast text to char* using a C cast, you can get hold of the char* by using the appropriate member function text.c_str()
you can simply write
outfile << text;
instead.
Why are you using pointers to std::string class?
You should not use sizeof with std::string, as it returns the size of the std::string object, and not the real size of the string inside.
You should try:
string text = "Text";
outfile.write(text.c_str(), text.size());
or
outfile << text;
Should probably also use c_str() to get the char pointer too, instead of that straight crazy cast.
Your code is wrong wrong way you are using to write & read the file
and file extension error you are trying to read text file .txt
correct code
Write to file
std::string text = "Text";
ofstream outfile("myfile.dat", ofstream::binary | ios::out);
outfile.write(&text,sizeof (string));//can take type
outfile.write(&text,sizeof (text));//can take variable name
outfile.close();
reading file
char* buffer = (char*) malloc(sizeof(string));
ifstream infile("myfile.dat", ifstream::binary | ios::in);
infile.read(buffer, sizeof (prueba));
std::string* elem = (string*) buffer;
cout << *elem;
infile.close();
Try This it will work
I had the same problem. I found the perfect answer here: Write file in binary format
Key issues: use string::length to get the length of the string when writing out and use resize() before reading the string. And both for reading and writing, use mystring.c_str() instead the string itself.
Try this code snippet.
/* writing string into a binary file */
fstream ifs;
ifs.open ("c:/filename.exe", fstream::binary | fstream::in | fstream::out);
if (ifs.is_open())
{
ifs.write("string to binary", strlen("string to binary"));
ifs.close();
}
Here is a good example.

Is it poosible to open the same file using wfstream and fstream

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);
...

Handling Automatic Naming of Files In C++ Sprintf

I am currently writing a program in C++. I want to save a number of files continuously throughout the run of my program. The format of the filename is as such:
char fnameC[sizeof "C:\..._SitTurn_104_c2_00_00_000.bmp"];
- SitTurn is an experiment name
- 104 is an experiment number
These two will be changing after each different run of the program. Currently, my program works like this:
char fnameCVS[sizeof"C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_02.csv"];
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
double elapsedTime;
SYSTEMTIME comptime;
int main(int argc, char *argv[])
{
GetSystemTime(&comptime);
sprintf_s(fnameCVS, "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_%02d.csv", comptime.wDay);
However, I tried this and I can't seem to get it to work. Can anyone help me?
...//rest of code set up
string expName = "SitStand";
string subjNumber = "101";
char fnameCVS[sizeof "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" + expName + "_" + subjNumber + "_c2_02.csv"];
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
double elapsedTime;
SYSTEMTIME comptime;
int main(int argc, char *argv[])
{
GetSystemTime(&comptime);
sprintf_s(fnameCVS, "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" + expName + "_" + subjNumber + "_c2_%02d.csv", comptime.wDay);
Since I am using this filename later in the program also, I would like to be able to just rename all files by changing the two strings: expName and subjNumber. Can someone help me explain how I can name my files using a string inputs (e.g. expName and subjNumber), so I only have to rename those corresponding string each time I change the experiment name, or subject number. Thanks!
Try this:
char fnameCVS[MAX_PATH+1];
SYSTEMTIME comptime;
GetSystemTime(&comptime);
sprintf_s(fnameCVS, _countof(fnameCVS), "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_%02d.csv", comptime.wDay);
Or this:
#include <string>
#include <sstream>
std::string expName = "SitStand";
std::string subjNumber = "101";
std::string fnameCVS;
SYSTEMTIME comptime;
GetSystemTime(&comptime);
std::ostringstream oss;
oss << "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" << expName << "_" << subjNumber << "_c2_" << std::setw(2) << std::setfill('0') << comptime.wDay << ".csv";
fnameCVS = oss.str();
You are mixing sprintf and std::string, which is never a good plan. You should either pick to use C's sprintf with char *, or C++'s std::string with std::stringstream.
Your fnameCVS array isn't going to be big enough: you'll take the sizeof of a std::string, which almost certainly will not be what you want.
Option 1: Use only sprintf. Allocate a big-enough string (e.g. char fnameCVS[256]) and use snprintf(fnameCVS, 256, "...Skeleton_%s_%d_c2_%02.csv", ...).
Option 2: Use only string and use a std::stringstream to build your filename.
This is a really bad idea:
char fnameCVS[sizeof"C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_02.csv"];
The main reason is that it is very difficult to visually inspect whether you have allocated the right number of bytes. Perhaps you make a slight change to the filename later in the sprintf line but then you forget to update this line or you make a typo. Boom, buffer overflow (which may go undetected until it is time to give a presentation).
A secondary bug is that when you use %02d in printf, the 2 is a minimum field width; if the number would require more than 2 digits then it outputs more than 2 digits, causing a buffer overflow. To be safe here you'd need to check that the number is between 0 and 99 before printing it.
Finally, sprintf_s is a non-standard function, there's really no reason to use it instead of sprintf or snprintf.
In C++ the equivalent formatting is a bit more wordy, but leaves no possibility of buffer overflows:
std::string fnameCVS;
// ...
std::ostringstream oss;
oss << "C:\\Users\\whatever...." << std::setw(2) << std::setfill('0')
<< comptime.wDay;
fnameCVS = oss.str();
If you really want to stick with the printf family plus a static char array (note: you can use printf and a dynamically-sized char container) then to make your code safe:
char const my_format[] = "C:\\Users\\whatever.....\\%02d.csv";
char fnameCVS[ sizeof my_format - 2 ]; // "NN" is two chars shorter than "%02d"
// ...
if ( comptime.wDay < 0 || comptime.wDay > 99 )
throw std::runtime_error("wDay out of range");
snprintf(fnameCVS, sizeof fnameCVS, my_format, comptime.wDay);
Your update indicates that you want to compute various other parts of the filename at runtime too; the C++ version that I suggest is easier to extend than the C-with-static-array version where you have to calculate the amount of memory you need by hand.

convert string to long long int

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
}

How to capture length of sscanf'd string?

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;