I have this code and it's compiling correctly :
char classfname[512] = "classifiers/cabmodel_VOC05motorbikes.xml";
strcpy(classfname,argv[i]);
but when I tried to define an array contains strings from the same size of the above size
and with your all help it didn't work !
std::vector<std::string> classfname = {
"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml"
};
char *classfname[6]={-----}
std::vector<std::string> classfname;
classfname.push_back(",,,");
with the function strcpy(classfname,argv[i]);
I got the error:
Error 2 error C2664: 'strcpy' : cannot convert parameter 1 from 'std::string' to 'char *
Converting string literals to a char* is no longer allowed, since it was never safe. Instead, make an array of const char*. (Although I'm not 100% positive this is the cause of your error, but your code doesn't match your error well, I think you changed something to put it on SO). std::string has a constructor from const char*, so this should work fine.
Also, it's good to note that (const::std string & is not right, so we know you changed stuff when you posted it here. Don't do that, or we can't help you much at all. It should be (const std::string&.
Also, MrC64 notes that you should use RAII instead of raw arrays and pointers. It's easier to use, and harder to mess up.
std::vector<std::string> classfname = {
"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml"
};
If your compiler can't handle that syntax yet (many can't), use the code that Mr_C64 suggested.
[EDIT] You have changed your question dramatically to be a completely different question. Generally this is bad, because anyone who comes to this page looking for answers will see that our answers don't match your question anymore. If you have additional questions, you should use the search feature, or make a new question page.
Now your code has a std::vector of std::strings. Treat a std::string like you would an int. Just copy it, or pass it around with no worries. You don't have do use a special function to copy a int, so you don't need a special function to copy a string. Just do std::string newstring = classfname[0]; to get a copy of the string at index 0 in the array classfname.
Your "old" code makes an array of chars initialized to a string literal, and over-rights it with the input from argv[i] The best way to do that code is:
std::string classfname = "classifiers/cabmodel_VOC05motorbikes.xml";
classfname = argv[i];
If you just want to make an array of each of the arguments, that's easy:
int main() {int argc, const char** argv) {
std::vector<std::string> classfname(argv, argv+argc);
One solution is to use const char* like this:
const char *classfname[7]={"classifiers/cabmodel_VOC05motorbikes.xml",
"classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml" ,
"classifiers/cabmodel_interm_nst40_VOC06cat01train5_trainval_orienthistmod_nopert_facereg.xml",
"classifiers/cabmodel_interm_nst100_VOC06bicycle01train5_trainval_orienthistmod.xml",
"classifiers/cabmodel_VOC06carside.xml",
"classifiers/cabmodel_interm_nst100_VOC06horse01train5_trainval_orienthistmod_randsel0100.xml",
};
Also if you want to have a std::vector containing these strings use can initialize it with the following statement:
const std::vector<std::string> classfname_vector(classfname, classfname + 7);
One more thing I noticed is that you declared an array with 7 elements but initialized it only with 6 string literals.
I'd just use std::vector<std::string> instead of a "raw" C array:
#include <string>
#include <vector>
std::vector<std::string> classfname;
classfname.push_back("classifiers/cabmodel_VOC05motorbikes.xml");
classfname.push_back("classifiers/cabmodel_interm_nst100_VOC06person01train5_orienthistmod.xml");
...
std::vector overloads operator[], so your call xmlloadmodel(classfname[i],model); should work.
Related
Say I got this
char* MapIds[5000] = { "Northeast Asia","Hanyang","Pusan","Pyongyang","Shanghai","Beijing","Hong Kong", /*...5000 values etc../* };
I tried
strcpy(MapIds[0], "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");
But it crashes
How Do I keep changing them around without messing up the strings in other elements.
I dont want to use std::string or vector those cause crazy slow compile times.
Because you try to copy into a literal string ("Northeast Asia").
In C++ a literal string is really a constant array of characters, any attempt to modify such an array will lead to undefined behavior (which can sometimes express themselves as crashes).
If you want to make MapIds[0] point to a new string, then you simply use assignment:
MapIds[0] = "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg";
Because literal strings are constant arrays of characters, C++ doesn't really allow you to have a char* to point to them, you must use const char*:
const char* MapIds[] = { ... };
However, a much better solution is to not use C-style strings and char pointers (const or not) at all, but only use std::string:
std::string MapIds[] = { ... };
Then you can modify the strings in the array itself, using plain assignment as shown above.
I have following scenario:
struct MyStruct
{
char name[25];
char address[12];
}
Somewhere::SomeMethod(std::shared_ptr<SomeArgumentClass> args)
{
// GetName() and GetAddress() both return std::strings
::MyStruct newValue = {args->GetName(), args->GetAddress()};
// add newValue to some structure that needs to have chars
}
Error:
error C2440: 'initializing' : cannot convert from 'std::string' to 'char'
error C2440: 'initializing' : cannot convert from 'std::string' to 'char'
I am not able to get my std::string converted to a char.
Thanks a lot!
Firstly, your terminology is incorrect. You don't want to convert to char, which is a single character. I realise that the error message claims you're trying to convert to char, but that's because your incorrect code has confused the compiler into thinking you're trying to initialise individual elements of the array name. Be wary of the specifics of an error message when you write the wrong code, because the compiler cannot read your mind — it can only go off of what you've written!
In reality you want to copy the characters inside your std::string, into the array of char, that is your member.
Like so:
Somewhere::SomeMethod(std::shared_ptr<SomeArgumentClass> args)
{
const auto& name = args->GetName();
const auto& address = args->GetAddress();
::MyStruct newValue;
std::copy(std::begin(name), std::end(name), &newValue.name[0]);
std::copy(std::begin(address), std::end(address), &newValue.address[0]);
// add newValue to some structure that needs to have chars
}
But you need to add bounds checking too. To do that, roughly I might consider replacing each std::copy call with something like:
std::copy_n(
&name[0],
std::min(name.size(), sizeof(newValue.name)),
&newValue.name[0]
);
You'll also need some null termination depending on how many characters were copied.
Generally though the salient point is that you need to actually copy those characters because there is no one-step way to do it. It stems in part from how arrays can't be assigned-to, but also from the fact that their dimensions are part of the type which makes things more complicated.
If this seems like a pain in the arse, that's because it is — ideally you would stick with std::string across the board because it's far superior, and was specifically introduced to make it easier to handle arrays of char. You can still pass a const char* (or char*!) pointing to the string's data into a C API. Of course if ::MyStruct itself is a third-party C type, you have no choice but to do it the hard way.
This question already has answers here:
Assigning char array a value in C
(2 answers)
Closed 8 years ago.
I get no error when I type
char a[10] = "Hi";
But when I change it to the following, I get an error: Array type char is not assignable.
char a[10];
a = "Hi";
Why is array type char not assignable? Is it because the language is written that way on purpose or am I missing a point?
An array is not a modifiable lvalue
use
char a[10];
strcpy(a, "Hi");
The C++ way of doing this, as I commented above, would be to use std::string instead of char[]. That will give you the assignment behavior you're expecting.
That said, the reason you're only getting an error for the second case is that the = in these two lines mean different things:
char a[10] = "Hi";
a = "Hi";
The first is an initialization, the second is an assignment.
The first line allocates enough space on the stack to hold 10 characters, and initializes the first three of those characters to be 'H', 'i', and '\0'. From this point on, all a does is refer to the position of the the array on the stack. Because the array is just a place on the stack, a is never allowed to change. If you want a different location on the stack to hold a different value, you need a different variable.
The second (invalid) line, on the other hand, tries to change a to refer to a (technically different) incantation of "Hi". That's not allowed for the reasons stated above. Once you have an initialized array, the only thing you can do with it is read values from it and write values to it. You can't change its location or size. That's what an assignment would try to do in this case.
The language does not allow assigning string literals to character arrays. You should use strcpy() instead:
strcpy(a, "Hi");
a is a pointer to the array, not the array itself. It cannot be reassigned.
You tagged with C++ BTW. For that case better use std::string. It's probably more what you're expecting.
Simple, the
char a[10] = "Hi";
is a little "extra feature", as it cannot be done like that on run-time.
But that's the reason for C/C++ standard libraries.
#include <string.h>
// ...
strcpy(a,"Test"); // STR-ing C-o-PY.
This comes from the C's standard library. If using C++ you should use std::string, unless you really want to suck all the possible performance from your destination PC.
this is because initialization is not an assignment. the first thing which works is an initialization, and the second one, which does not work, as expected, is assignment. you simply cant assign values to arrays you should use sth like strcpy or memcpy. or you can alternatively use std::copy from <algorithm>
It is so simple,(=) have two different mean assignment and initialization. You can also write your code like that
#include <iostream>
using namespace std;
int main ()
{
char message[3] = {'H', 'i', '\0'};
cout << message<< endl;
return 0;
}
in this code you have no need to write a difficult code or function and even no need of string.h
I have found that the easiest way to build my program argument list is as a vector of strings. However, execv expects an array of chars for the second argument. What's the easiest way to get it to accept of vector of strings?
execv() accepts only an array of string pointers. There is no way to get it to accept anything else. It is a standard interface, callable from every hosted language, not just C++.
I have tested compiling this:
std::vector<string> vector;
const char *programname = "abc";
const char **argv = new const char* [vector.size()+2]; // extra room for program name and sentinel
argv [0] = programname; // by convention, argv[0] is program name
for (int j = 0; j < vector.size()+1; ++j) // copy args
argv [j+1] = vector[j] .c_str();
argv [vector.size()+1] = NULL; // end of arguments sentinel is NULL
execv (programname, (char **)argv);
The prototype for execv is:
int execv(const char *path, char *const argv[]);
That means the argument list is an array of pointers to null-terminated c strings.
You have vector<string>. Find out the size of that vector and make an array of pointers to char. Then loop through the vector and for each string in the vector set the corresponding element of the array to point to it.
I stumbled over the same problem a while ago.
I ended up building the argument list in a std::basic_string<char const*>. Then I called the c_str() method and did a const_cast<char* const*> on the result to obtain the list in a format that execv accepts.
For composed arguments, I newed strings (ordinary strings made of ordinary chars ;) ), took their c_str() and let them leak.
The const_cast is necessary to remove an additional const as the c_str() method of the given string type returns a char const* const* iirc. Typing this, I think I could have used std::basic_string<char*> but I guess I had a reason...
I am well aware that the const-casting and memory leaking looks a bit rude and is indeed bad practise, but since execv replaces the whole process it won't matter anyway.
Yes, it can be done pretty cleanly by taking advantage of the internal array that vectors use. Best to not use C++ strings in the vector, and const_cast string literals and string.c_str()'s to char*.
This will work, since the standard guarantees its elements are stored contiguously (see https://stackoverflow.com/a/2923290/383983)
#include <unistd.h>
#include <vector>
using std::vector;
int main() {
vector<const char*> command;
// do a push_back for the command, then each of the arguments
command.push_back("echo");
command.push_back("testing");
command.push_back("1");
command.push_back("2");
command.push_back("3");
// push NULL to the end of the vector (execvp expects NULL as last element)
command.push_back(NULL);
// pass the vector's internal array to execvp
execvp(command[0], const_cast<char* const*>(command.data()));
return 1;
}
Code adapted from: How to pass a vector to execvp
Do a const_cast to avoid the "deprecated conversion from string constant to 'char*'". String literals are implemented as const char* in C++. const_cast is the safest form of cast here, as it only removes the const and does not do any other funny business. execvp() will not edit the values anyway.
If you want to avoid all casts, you have to complicate this code by copying all the values to char* types not really worth it.
Although if the number of arguments you want to pass to execv/execl is known, it's easier to write this in C.
You can't change the how execv works (not easily anyway), but you could overload the function name with one that works the way you want it to:
int execv(const string& path, const vector<string>& argv) {
vector<const char*> av;
for (const string& a : argv) {
av.push_back(a.c_str());
av.push_back(0);
return execv(path.c_str(), &av[0]);
}
Of course, this may cause some confusion. You would be better off giving it a name other than execv().
NB: I just typed this in off the top of my head. It may not work. It may not even compile ;-)
I want to convert a C-style string into a byte-vector.
A working solution would be converting each character manually and pushing it on the vector. However, I'm not satisfied with this solution and want to find a more elegant way.
One of my attempts was the following:
std::vector<byte> myVector;
&myVector[0] = (byte)"MyString";
which bugs and gets me an
error C2106: '=': left operand must be l-value
What is the correct way to do this?
The most basic thing would be something like:
const char *cstr = "bla"
std::vector<char> vec(cstr, cstr + strlen(cstr));
Of course, don't calculate the length if you know it.
The more common solution is to use the std::string class:
const char *cstr;
std::string str = cstr;
STL containers such as vector always take ownership, i.e. they manage their own memory. You cannot modify the memory managed internally by an STL container. For that reason, your attempt (and any similar attempt) is doomed to failure.
The only valid solution is to copy the memory or to write a new STL-style container that doesn’t take ownership of the memory it accesses.
Something along these lines should work
std::vector<byte> myVector = std::vector((byte*)cstring, (byte*)ctring + strlen(cstring))
Also, this is still going to just iterate through the c string and insert the values into the vector. Like Konrad said, that's just how you have to do it since vectors manage their own memory.
In case you would not like to copy the original string and would just like to iterate over it as an array of bytes, then C++20 has std::span to offer.
auto const const_bytes = std::as_bytes(std::span{str.data(), str.size()});
std::span<const std::byte> provides std::vector like iterating capabilities which I think is what you might be looking for.
Note: The original string would have to remain valid for the entire scope of std::span variable
std::vector<byte> myVector;
const char* str = "MyString";
myVector.assign( str, str+strlen(str) );
The most obvious question would be why you don't just use std::string:
std::string myString("MyString");
but if you really think you need a vector:
char myString[] = "MyString";
std::vector<byte> myVector(myString, myString+sizeof(myString));
You might also want to consider using std::tr1::array:
std::tr1::array<byte, sizeof("MyString")> myArray = {"MyString"};
C++ 0x will also have std::array.
const char *cstr = "bla"
std::vector<char> vec;
vec.resize(strlen(cstr)+1);
strcpy(&vec[0],cstr);