error while inserting into set c++ - c++

/info is a string/
while(getline(cin,info)){
char *a = new char[info.size()+1];
a[info.size()] = 0;
memcpy(a,info.c_str(),info.size());
//cout<<sizeof(a)<<endl;
set<char *>m;
m.insert(a,a+8);
}
//Error:invalid conversion from char to char*

I suspect the thing you're missing is that when you insert a range, it inserts each item in that range. It doesn't try to insert them as a single item but it inserts each item in the range individually.
set<char *>m;
m.insert(a,a+8);
Okay, so m is a set of char*. You've said that you want to insert everything in the range from a to a+8. That's a range of characters. So you're trying to insert characters into a set of pointers to characters. That can't work.
Perhaps you just want m.insert(a);? Since m is a set of char* and a is a char*, I can't imagine what you might want to do other than insert it.

m.insert(a,a+8);
You tried to use a wrong overload of set::insert(). It is mostly useful when you want to do something like this:
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::set<int> m;
m.insert(a[0]);
m.insert(a[1]);
...
m.insert(a[6]);
m.insert(a[7]);
This is lengthy and we want to avoid repetitions. Equivalently, you can write
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::set<int> m;
m.insert(a, a+8);
Now let's go back to your code...
while(getline(cin,info)){
char *a = new char[info.size()+1];
...
set<char *>m;
m.insert(a,a+8);
Conversely, you can "expand" it into
while(getline(cin,info)){
char *a = new char[info.size()+1];
...
set<char *>m;
m.insert(a[0]);
m.insert(a[1]);
...
m.insert(a[6]);
m.insert(a[7]);
Now you see you ended up in insert-ing a char object to std::set<char *>. This is the reason why you got the error message.
Proposed fix
You defined set<char *> m inside the while loop. That means you are dealing with a freshly constructed m in each iteration of the while loop, which doesn't makes sense. You need to move the definition of m to before while.
It is not recommended to use new char[...] until you spend 5--6 years in C++. C++ already prepared std::string and/or std::vector for you to replace 99% of the use cases of raw new char[...]. So your set should be set<string> m.
std::string has an assignment operator (and a copy constructor) which takes a std::string or NUL-terminated const char * and does memcpy() for you, and you can think set::insert() internally invokes it.
std::string also supports a substring operation returning a fresh std::string such that string("abcde").substr(3) == "abc".
http://en.cppreference.com/w/cpp/string/basic_string/substr
That means you don't need an intermediate variable a at all.
After these corrections, you'll get
set<string> m;
while(getline(cin,info)){
m.insert(info.substr(8));
}

Related

C++ Array Reinitialization using Braces [duplicate]

So I am playing around with some arrays, and I cannot figure out why this won't work.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
values = numbers;
The following error appear:
Error 1 error C2106: '=' : left operand must be l-value c:\users\abc\documents\visual studio 2012\projects\consoleapplication7\consoleapplication7\main.cpp 9 1 ConsoleApplication7
Why can't I do like that? What does the error mean?
Arrays have a variety of ugly behavior owing to C++'s backward compatibility with C. One of those behaviors is that arrays are not assignable. Use std::array or std::vector instead.
#include <array>
...
std::array<int,5> numbers = {1,2,3};
std::array<int,5> values = {};
values = numbers;
If, for some reason, you must use arrays, then you will have to copy the elements via a loop, or a function which uses a loop, such as std::copy
#include <algorithm>
...
int numbers[5] = {1, 2, 3};
int values[5] = {};
std::copy(numbers, numbers + 5, values);
As a side note, you may have noticed a difference in the way I initialized the values array, simply providing an empty initializer list. I am relying on a rule from the standard that says that if you provide an initializer list for an aggregate, no matter how partial, all unspecified elements are value initialized. For integer types, value initialization means initialization to zero. So these two are exactly equivalent:
int values[5] = {0, 0, 0, 0, 0};
int values[5] = {};
You can't assign arrays in C++, it's stupid but it's true. You have to copy the array elements one by one. Or you could use a built in function like memcpy or std::copy.
Or you could give up on arrays, and use std::vector instead. They can be assigned.
Array names are constant not modifiable l-value, you can't modify it.
values = numbers;
// ^
// is array name
Read compiler error message: "error C2106: '=' : left operand must be l-value" an l-value is modifiable can be appear at lhs of =.
You can assign array name to a pointer, like:
int* ptr = numbers;
Note: array name is constant but you can modify its content e.g. value[i] = number[i] is an valid expression for 0 <= i < 5.
Why can't I do like that?
Basically this constrain is imposed by language, internally array name uses as base address and by indexing with base address you can access content continue memory allocated for array. So in C/C++ array names with be appear at lhs not a l-value.
values = numbers;
Because numbers and values are pointers.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
for(int i = 0;i < 5; i ++){
values[i] = numbers[i];
}
std::array is a good idea, but this is also possible:
struct arr { int values[5]; };
struct arr a{{1, 2, 3}};
struct arr b{{}};
a = b;
Otherwise, use std::memcpy or std::copy.
I think the reason for non-assignability is that C wants to make sure that any pointers to any element in the array would pretty much always remain valid.
Think about vectors that allow dynamic resizing: the older pointers become invalid (horribly) after resizing happens automatically.
PS. With the design philosophy for vectors, the following block works well.
vector<int> v = {1, 5, 16, 8};
vector<int> v_2 = {7, 5, 16, 8};
v_2 = v;

Initialise a dynamically allocated array [duplicate]

In C++, I can statically initialize an array, e.g.:
int a[] = { 1, 2, 3 };
Is there an easy way to initialize a dynamically-allocated array to a set of immediate values?
int *p = new int[3];
p = { 1, 2, 3 }; // syntax error
...or do I absolutely have to copy these values manually?
You can in C++0x:
int* p = new int[3] { 1, 2, 3 };
...
delete[] p;
But I like vectors better:
std::vector<int> v { 1, 2, 3 };
If you don't have a C++0x compiler, boost can help you:
#include <boost/assign/list_of.hpp>
using boost::assign::list_of;
vector<int> v = list_of(1)(2)(3);
You have to assign each element of the dynamic array explicitly (e.g. in a for or while loop)
However the syntax int *p = new int [3](); does initialize all elements to 0 (value initialization $8.5/5)
To avoid endless push_backs, I usually initialize a tr1::array and create a std::vector (or any other container std container) out of the result;
const std::tr1::array<T, 6> values = {T(1), T(2), T(3), T(4), T(5), T(6)};
std::vector <T> vec(values.begin(), values.end());
The only annoyance here is that you have to provide the number of values explicitly.
This can of course be done without using a tr1::array aswell;
const T values[] = {T(1), T(2), T(3), T(4), T(5), T(6)};
std::vector <T> vec(&values[0], &values[sizeof(values)/sizeof(values[0])]);
Althrough you dont have to provide the number of elements explicitly, I prefer the first version.
No, you cannot initialize a dynamically created array in the same way.
Most of the time you'll find yourself using dynamic allocation in situations where static initialization doesn't really make sense anyway. Such as when you have arrays containing thousands of items. So this isn't usually a big deal.
Using helper variable:
const int p_data[] = {1, 2, 3};
int* p = (int*)memcpy(new int[3], p_data, sizeof(p_data));
or, one line
int p_data[] = {1, 2, 3}, *p = (int*)memcpy(new int[3], p_data, sizeof(p_data));
Never heard of such thing possible, that would be nice to have.
Keep in mind that by initializing the array in the code that way
int a[] = { 1, 2, 3 };
..... only gains you easier code writing and NOT performance.
After all, the CPU will do the work of assigning values to the array, either way you do it.

Declaring array of pointers to char arrays

How come I can do this:
char a[] = {1, 2};
char b[] = {3, 4, 5};
const char *r[] = {
a, b
};
But I can't do it this way:
const char *r[] = {
{1,2}, {3,4,5}
};
Is there any shortcut for initializing an array of pointers to arrays of different length?
There is no easy solution to achieve the syntax you're looking for: these pointers have to point at some arrays, and these arrays must have an adequate lifetime.
You probably want them to be automatic, which implies declaring them as local variables the way you did.
You could achieve sort of what you want with dynamic allocation, i.e:
const char *r[] = {
new char[]{1,2}, new char[]{3,4,5}
};
... in which case the arrays will have sufficient lifetime, but then you have the burden of delete[]ing them at the right time. Not really a solution.
The first form works because, when used like this, the name of each array is converted to a pointer (to its first element). Since the result of the conversion is a char * it can be stored in an array of char *.
The second form doesn't work since {1,2} and {3,4,5} are (initialisers for) arrays, and arrays are not pointers. An unnamed array (which these are) cannot be implicitly be converted to a pointer.
The first form IS the only shortcut to initialise an array of pointers, so each pointer points to the first element of an array.
You would be normally better off using standard containers (e.g. a std::vector<std::string>) and avoid the complexity of pointers (and conversions of array names to pointers) entirely.
this code doesn't work,
const char r[][] = {{1,2}, {3,4,5}};
fails with :
x86-64 gcc 5.1!!error: declaration of 'r' as multidimensional array
must have bounds for all dimensions except the first
fix it like so:
const char r[][3] = {{1,2}, {3,4,5}};
side note: it's a bad practice to use C-like arrays in c++ use std::array if you know your values at compile time.
EDIT:
you can do this ugly hack(it compiles, but I don't know how many rockets it will launch).
const char *r[] = { (const char[]){1,2}, (const char[]){1,2,3}};
you can't write:
const char *r[] = { {1,2}, {3,4,5} };
because you cannot write:
r[0] = 1, 2, 3; // but you can r[0] = "1, 2, 3";
to initialize your array of pointers to char you can:
const char *r[] = {
{"1,2"}, {"3,4,5"}};
so r is a an array of pointers to char.

Function that returns the max of a variable number of scalars

I need to create a function that takes as an input a variable number of scalars and returns the biggest one. Just like std::max() does for 2 elements, but I need it for an undefined number of elements, can be 2, or 5, or 10 etc.. Any suggestions on how to approach this?
I'm using Visual Studio 2010. I tried with:
std::max({2, 8, 5, 3})
Error: no instance of overloaded function "std::max" matches the argument list
std::vector<int> v {2, 8, 5, 3};
Error: expected a ; (after v)
And more important, if I put this into a function, how do I have a variable number of arguments and how do I call them? I guess it should be somehow with a template?
What I need it for: I'm working with a bunch of vectors, maps, etc. and I need to find out which has the most elements. So I was thinking that I should end up with something like
int biggest = max(vector1.size(), vector2.size(), map1.size(), ...);
Use std::max_element, if you have a container already populated
std::vector<int>::iterator it = std::max_element( vector1.begin(), vector1.end() );
Else use plain array like following :
int a[] = {2, 8, 5, 3 }; // add whatever elements you want
int *pos = std::max_element( a, a+sizeof(a)/sizeof(a[0]) ) ;

Assign array to array

So I am playing around with some arrays, and I cannot figure out why this won't work.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
values = numbers;
The following error appear:
Error 1 error C2106: '=' : left operand must be l-value c:\users\abc\documents\visual studio 2012\projects\consoleapplication7\consoleapplication7\main.cpp 9 1 ConsoleApplication7
Why can't I do like that? What does the error mean?
Arrays have a variety of ugly behavior owing to C++'s backward compatibility with C. One of those behaviors is that arrays are not assignable. Use std::array or std::vector instead.
#include <array>
...
std::array<int,5> numbers = {1,2,3};
std::array<int,5> values = {};
values = numbers;
If, for some reason, you must use arrays, then you will have to copy the elements via a loop, or a function which uses a loop, such as std::copy
#include <algorithm>
...
int numbers[5] = {1, 2, 3};
int values[5] = {};
std::copy(numbers, numbers + 5, values);
As a side note, you may have noticed a difference in the way I initialized the values array, simply providing an empty initializer list. I am relying on a rule from the standard that says that if you provide an initializer list for an aggregate, no matter how partial, all unspecified elements are value initialized. For integer types, value initialization means initialization to zero. So these two are exactly equivalent:
int values[5] = {0, 0, 0, 0, 0};
int values[5] = {};
You can't assign arrays in C++, it's stupid but it's true. You have to copy the array elements one by one. Or you could use a built in function like memcpy or std::copy.
Or you could give up on arrays, and use std::vector instead. They can be assigned.
Array names are constant not modifiable l-value, you can't modify it.
values = numbers;
// ^
// is array name
Read compiler error message: "error C2106: '=' : left operand must be l-value" an l-value is modifiable can be appear at lhs of =.
You can assign array name to a pointer, like:
int* ptr = numbers;
Note: array name is constant but you can modify its content e.g. value[i] = number[i] is an valid expression for 0 <= i < 5.
Why can't I do like that?
Basically this constrain is imposed by language, internally array name uses as base address and by indexing with base address you can access content continue memory allocated for array. So in C/C++ array names with be appear at lhs not a l-value.
values = numbers;
Because numbers and values are pointers.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
for(int i = 0;i < 5; i ++){
values[i] = numbers[i];
}
std::array is a good idea, but this is also possible:
struct arr { int values[5]; };
struct arr a{{1, 2, 3}};
struct arr b{{}};
a = b;
Otherwise, use std::memcpy or std::copy.
I think the reason for non-assignability is that C wants to make sure that any pointers to any element in the array would pretty much always remain valid.
Think about vectors that allow dynamic resizing: the older pointers become invalid (horribly) after resizing happens automatically.
PS. With the design philosophy for vectors, the following block works well.
vector<int> v = {1, 5, 16, 8};
vector<int> v_2 = {7, 5, 16, 8};
v_2 = v;