I'm new to C++ programming (haven't done it in 10+ since college.) and I'm trying to write a very basic program to grab a file name that has been passed as an argument. I'm just not getting how to get the file name. I'm using VS2012 Exp for Desktop.
Below is my code.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <xstring>
#include <string>
//using namespace openutils;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
wcout << "customconsole app has "<< argc <<" arguments passed. second one is: " << argv[1];
ofstream me_attach_file;
wstring newfilename = argv[1] && ".newext";
me_attach_file.open (".mailexpress");
me_attach_file << "Writing this to a file.\n";
me_attach_file.close();
return 0;
}
Replace this
wstring newfilename = argv[1] && ".newext";
with
wstring newfilename = argv[1];
newfilename += L".newext";
Some languages use & for string concatenation. C++ does not. In fact, there is NO operator that concatenates string literals and character pointers: + as string concatenation is defined by string objects and works only with them.
In addition, string literals have to be prefixed with L to use wide characters and be compatible with wstring.
&& doesn't add two strings together. The + operator does.
Also, C++ decides which of the many operator + functions to use by the type of the left-hand argument. You have two different types here, a _TCHAR string, a string literal ("this is a string literal") which is type char*, and you want to put it into a wstring.
First, a _TCHAR and char* aren't the same type, so it should be L".newext".
Second, you can't add two char*s, because that is adding two pointers, and pointer arithmatic does something different than what you want. So the first argument needs to be coverted to a wstring before you start adding things together.
Either:
wstring myStr = argv[1];
myStr += L".newext"
Or:
wstring myStr = wstring(argv[1]) + L".newext" + L"Additional stuff"
in the line
me_attach_file.open (".mailexpress");
you should pass the filename to the object.
me_attach_file.open (newfilename);
in your version, ofstream will open a file named ".mailexpress" without prefix (which is hidden on unix systems).
Related
I am building a fast copy application using xcopy. I want to pass two variable source and destination to system(); I am trying like this
char *source = "D:\\SOFTWARE\\Internet";
char *destination = " D:\\test /s /e /d /y";
system("xcopy "+source+destination);
But it doesnt work. It work fine in java. same code. Thanks.
Rewriting Mike's code to eliminate all the issues we tend to flag in code being reviewed!
#include <string>
#include <cstdlib>
using std::string;
int main()
{
const string str{ "dir" };
const string str2{ " /w" };
const string final_string = str + str2;
std::system(final_string.c_str());
}
Your problem in your original code is that operator+ doesn't work with C style strings, which are just char* or char[] and not objects. You are asking to add pointers together, which is not a sensible thing.
As Mike points out, turn your raw char array input into std::string objects as soon as you need to do stuff with it, and then + will work.
In this particular case, you only need to copy one of the character arrays into objects (see docs on operator+= form 3):
string s {"xcopy "};
s += source;
s += destination; // this works, as there is an optimized form of operator+ for this.
std::system(s.c_str()); // access a nul-terminated character array to make the system call.
One more way of string concatenation is use of std::ostringstream. Source and destination paths are quoted in the code bellow to be more safe:
#include <sstream>
int main() {
const char *source = "\"D:\\SOFTWARE\\Internet\"";
const char *destination = " \"D:\\test\" /s /e /d /y";
std::ostringstream cmd;
cmd << "xcopy " << source << destination;
system(cmd.str().c_str());
}
Compile and run
You need to use std::string (from string header). Also, you need to go from string to a const char pointer.
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdlib>
#include <string>
int main()
{
using namespace std;
string str{ "dir" };
string str2{ " /w" };
string final_string = str + str2;
char* cstr = new char[final_string.size() + 1];
strcpy(cstr, final_string.c_str());
system(cstr);
}
In the following code:
#include <string>
using namespace std;
int main(){
char command[300];
string stringz = "mystringy";
sprintf(command,"echo \"something with a string %s\" ", stringz);
system(command);
return 0;
}
why is the output
something with a string 8�
rather than the expected
something with a string mystringy
A silly question, but I couldn't find an answer around.
The '%s' modifier of printf takes a char*, not a std::string.
You can write:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Which gives you a const char* to the contents of a std::string. This shows one of the major weaknesses of sprintf -- no type checking!
sprintf format %s expects a C string, that's a 0-terminated array of char, not a std::string.
stringz.c_str() and since C++11 &stringz[0] and stringz.data() are a few ways to get at the C string held by the std::string.
To add on Deduplicator answer, try putting
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
and you should be set.
This is because sprintf is expecting a char * as an argument to expand the %s token. It would work like
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Which passes the "char *" version of the string to sprintf.
The reason why it shows those strange characters is because the whole std::string object is copied into sprintf's stack frame. Then, sprintf, which accepts variable number of arguments, looks into its own stack space and assumes that what it is going to find there is a char *, but actually is some garbage that results from reinterpreting the string data as char *, and when it is dereferenced, it results into that sequence. It could as well segfault if you are unlucky.
You should not use sprintf in the first place. This is C++, not C. std::string supports concatenation in a very natural way, with the + operator, like in some other programming languages:
#include <string>
int main(){
std::string stringz = "mystringy";
std::string command = "echo \"something with a string " + stringz + "\" ";
system(command.c_str());
return 0;
}
If you insist on using char-array functions like sprintf, use stringz.c_str(). As a matter of fact, this is also what system requires. But note how my example converts the string only at the last possible occasion.
You can use:
sprintf(command,"echo \"something with a string %s\" ", stringz.c_str());
Note that %s takes the C strings and not std::string.
Better still use, iostreams:
string stringDemo("MYSTRING");
std::cout << stringDemo << "\n";
Using the strcpy_s() function I want to collate the first three strings into the final one to print my full name. This is what I have and it doesn't work as I'm using char* strings and not std::strings.
#include <iostream>
using namespace std;
int main()
{
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
strcpy_s(str_fullName, (str_first + str_middle + str_last).c_str());
cout << str_fullName;
}
Any suggestions?
This should be close to what you're looking for, strictly using strcpy_s to concatenate strings together:
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
int index = strcpy_s(str_fullName, sizeof str_fullName, str_first);
index += strcpy_s(str_fullName + index, sizeof str_fullName - index, str_middle);
index += strcpy_s(str_fullName + index, sizeof str_fullName - index, str_last);
cout << str_fullName;
}
The index variable serves a couple of purposes: (1) to provide a new index into the output str_fullName string as the string is built, and (2) subtracted from sizeof str_fullName, it "adjusts" the available buffer size as the string is built.
Caveats are that you should add overflow checking via the output from strcpy_s, and (as noted by others) there are better patterns to follow for doing this, but probably as an academic exercise there's something good to be learned here.
You need to use both strcat and strcpy
See code comments for more info.
// disable SDL warnings in Visual studio
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
// TODO: insert checking code,
// to make sure destination can hold all characters + one termination.
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
// copy first string because we need null terminated destination
strcpy(str_fullName, str_first);
// append the rest, string is auto null terminated.
strcat(str_fullName, str_middle);
strcat(str_fullName, str_last);
cout << str_fullName;
}
If I am not mistaken the function strcpy_s expects three arguments. So either supply one more argument to the function call or use instead the function strcpy.
And there is no need to use the standard class std::string to perform the task.
The code can look the following way
strcpy( str_fullName, str_first );
strcat( str_fullName, str_middle );
strcat( str_fullName, str_last );
Or you could use strcpy_s and strcat_s provided that you will specify the correct number of arguments.
Pay attention to that you need to include the header
#include <cstring>
I get an error when trying to print concatenated strings:
std::cout << "some string" + "another string";
I get this error:
Operator does not take these operands.
I thought "some string" was a std::string literal. What is going on?
Binary + is not supposed to take these operands. C++ language does not have such + operator and never had one. You cannot add two string literals to each other.
Why you mention std::string in the question title is not clear to me. There's no std::string in your example. String literals are not std::string objects. String literals are just arrays of const char. They have no relation to std::string and they will not be magically converted to std::string for you.
If you want to use std::string in this case you have to convert at least one of your literals to std:string explicitly
cout << std::string("some string") + "another string";
In the case the overload resolution rules will make the compiler to consider the binary + operator for std::string objects and convert the second operand to std::string implicitly.
Those are not std::string-operands, where + really concatenates, but string literals.
String literals represent arrays of constant characters (including an implicit 0-terminator), which are not addable (const char[]). Neither are the pointers they decay to.
Still, concatenating them is really easy: Just leave out anything between them but whitespace, and the compiler will do it for you.
As an aside, since C++14 one can actually write std::string-literals:
#include <string>
using namespace std::literals::string_literals;
// the last two are inline-namespace, could leave them off to get more.
...
"std::string-literal"s // Note the `s` behind the string-literal.
To create a std::string literal, you have to do the following:
#include <string>
#include <iostream>
int main() {
using namespace std::string_literals;
std::cout << "some string"s + "another string"s;
}
notice the trailing s.
The sequence "some string" is not a std::string literal, but rather a const char[12] buffer of raw characters. This comes from C, where there was no std::string. In addition, it means that if you prefer a different string library, std::string has no built-in advantage.
With you post-fix with that s (after bringing the literals into view), you get a std::string literal.
This is a C++14 feature. In C++03 you can get a similar effect by doing
#include <string>
#include <iostream>
int main() {
std::cout << std::string("some string") + std::string("another string");
}
I'm trying to create a file whose name is a string constant, but a string consisting of a constant string "List" an integer + + an extension. Here's my code:
#include <iostream>
#include <vector>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
int main (){
int cont=0;
std::string result;
std::string name = "Lista";
std::string ext = ".txt";
char numstr[21]; // enough to hold all numbers up to 64-bits
sprintf(numstr, "%d", cont);
result = name + numstr+ext;
freopen (result, "w", stdout);
cout<<result<<endl;
return 0;
}
When I try to build tells me the following error:
error: cannot convert std::string' toconst char*' for argument 1'
toFILE* freopen(const char*, const char*, FILE*)'|
How I can solve this?
As the compiler error states there is no implicit conversion from std::string to char const* (ie. a c-style-string in this context).
Though std::string has a member-function named c_str which will generate a null-terminated string and return a pointer to it that is very usable when dealing with legacy C functions.
Examples and notes
freopen (result.c_str (), "w", stdout);
char const * p = result.c_str ();
Please note that the c-style-string pointed towards by std::string::c_str will be invalidated if you make any modifications to the hosting object (in this case result), therefore it is normally not wise to store the value returned in a non-temporary variable.
You can read more about the function if you follow the link below:
cppreference.com - std::basic_string::c_str
i have a small app that does this exactly. there are several ways to do this.. the simplest of which is
const char * newvar = stringname.c_str();
If you're going to use sprintf, it's probably easiest to skip using std::string at all:
char name[32];
sprintf(name, "lista%d.txt", cont);
freopen(name, "w", stdout);
If you're going to use std::string (probably preferable for most C++ anyway), you probably want to use std::stringstream to create the name:
std::ostringstream name;
name << "lista" << cont << ".txt";
freopen(name.str().c_str(), "w", stdout);
However, I'd tend to avoid freopen in general, and avoid using C-style streams (such as stout) in C++. It's generally better to write to an ostream. Answers to a previous question show how to connect cout to a different output file, if you truly need to.