This question already has answers here:
Why can't I assign an array variable directly to another array variable with the '=' operator?
(5 answers)
Closed 9 years ago.
The question is very simple but I'm confused that why the struct is behaving like this as all of its members are by default public, have a look at following code
struct Student
{
char name[20];
}
int main()
{
Student s;
s.name="ahmed";
}
This code gives an error that name should be a modifiable lvalue.
But if I assign value in a loop char by char, then it works fine like this
s.name[0]='a';//works fine
Arrays in C are non-assignable and non-copy-initializable and in C++ this behavior was inherited. On the right-hand side arrays decay to pointers but in your case your copy-initialization is just not allowed.
If you try this:
{
char name[20];
name="ahmed";
}
you're actually copy-initializing the array - and that's disallowed.
The only exception is initializing them with a string literal
char c[] = "abc";
In your case you should rather use a function called strcpy to accomplish that:
{
char name[20];
strcpy(&name[0],"ahmed"); // Obviously make sure that there's enough space
}
It's worth noting that you can also use strings to accomplish this task:
#include<iostream>
#include<string>
using namespace std;
struct Student{
string name;
};
int main()
{
Student s;
s.name = "ahmed";
}
Structure is not a problem in your case. Arrays in C are not assignable.
Instead of s.name = "ahmed" , use strcpy(s.name,"ahmed")
name is an array, and you can't assign to an array name. Instead, you should use std::strcpy in cstring to copy the contents of the C-style string.
std::strcpy(s.name, "ahmed");
Note that the problem has nothing to do with the fact that name is part of a struct. You would have the same problem with a native char array.
You must use:
struct Student
{
char *name;
};
int main()
{
Student s;
s.name = "ahmed";
return 0;
}
Related
I've written this code but I have some errors when I try to initialize an array of Critter objects and don't know what they're about.
My code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Critter {
private:
string crName;
public:
Critter(string = "Poochie");
string getName() const { return crName; }
};
Critter::Critter(string n) {
crName = n;
}
int main() {
Critter c[10] = { "bob","neo","judy","patrik","popo" }; //here
return 0;
}
The errors:
E0415 - no suitable constructor exists to convert from "const char [4]" to "Critter"
...
4 more like this.
This code worked on a friend's Visual Studio 2017, but not in mine which is the 2019 version.
Thanks.
The initialization you have is for an array of strings, for the objects you need:
Critter c[10] = {Critter("bob"), Critter("neo"), Critter("judy"),
Critter("patrik"), Critter("popo")};
Or
Critter c[10] = {{"bob"}, {"neo"}, {"judy"}, //(*)
{"patrik"}, {"popo"}};
*This second method is credited to #drescherjm comment followed by #dxiv's answer, both mentioned it first.
This second initialization may be what your friend used, and maybe you forgot the braces, the IDE version difference doesn't seem relevant here.
Note that C++ provides a container for fixed size arrays, std::array:
std::array<Critter, 10> c = {Critter("bob"), Critter("neo"),
Critter("judy"), Critter("patrik"), Critter("popo")};
On a side note:
You should avoid using namespace std;
Critter c[10] = { "bob","neo","judy","patrik","popo" };
This defines an array of const char *. To initialize an array of Critter with those strings, instead:
Critter c[10] = { {"bob"}, {"neo"}, {"judy"}, {"patrik"}, {"popo"} };
[ EDIT ] It was pointed out that the same answer was first posted in a comment, only it was hidden in an external link with no indication of what's behind it, which I did not see before posting the above. Credit goes to #drescherjm so I'll leave this here as a CW.
string c[10] = {"bob","neo","judy","patrik","popo"}; Would be correct.
{"bob","neo","judy","patrik","popo"} is an array containing string elements.
You need to do
Critter c[10]={ Critter("bob"),Critter("neo"),Critter("judy"),Critter("patrik"),Critter("popo")};
C++ only allows one "user-defined conversion" at a time.
You're providing char const[N]s (let's call them char const*s for the sake of argument), which need to be turned into std::strings (which count as "user-defined" in this context), which need to be turned into Critters.
That's two conversions, not one.
That's just a limitation of C++, I'm afraid. You'll have to temporarily instantiate either strings or Critters within that initialiser.
I'm not very familiar with pointers, but I have an assignment that requires me to create an array of pointers of type char. I just can't seem to get the code running.
#include <iostream>
using namespace std;
int main() {
int n = 0;
char *seasons[] = { "Winter",
"Spring",
"Summer",
"Fall"};
cout << seasons[n] << endl;
return 0;
}
I copied and pasted this code from the textbook, but I keep getting errors for the strings that are in the array.
The error is E0144: a value of type "const char *" cannot be used to initialize an entity of type "char *"
I wonder if your textbook-maker did a quick-and-dirty conversion of existing C code to C++. In C, string literals are arrays of type char (even though they are immutable), but in C++ they are arrays of type const char.
The solution here is to change the type of seasons to be const char *[] to make an array of pointers to these const char arrays:
const char *seasons[] = { "Winter",
"Spring",
"Summer",
"Fall"};
As an aside, I am also not a fan of your book doing using namespace std;. It pollutes the global namespace with the entirety of the std namespace which can (and in my experience has) lead to conflicts that will break code.
I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.
I am attempting to initialize variables within my object, using a function with const pointers as parameters.
I keep getting errors in many of the ways i attempted, here is my code:
class Molecule
{
private:
char s[21];
char d[21];
double w= 0;
public:
Molecule();
void set(const char*, const char*, double);
void display() const;
};
int main() {
int n;
cout << "Molecular Information\n";
cout << "=====================" << endl;
cout << "Number of Molecules : ";
cin >> n;
Molecule *molecule = new Molecule[n];
for (int i = 0; i < n; i++) {
char symbol[21];
char description[21];
double weight;
molecule[i].set(&symbol,&discription,weight);
//...
}
//implementation of class
#include "Molecule.h"
#include <iostream>
#include <cstring>
void Molecule::set(const char*, const char*, double)
{
s = &symbol;
d = &discription;
w = &weigth;
}
My question is: How would i correctly call the member function from an array of objects, using constant chars as parameter, and what is the correct way to set them to my variables in my class.
P.S: I have been trying to figure this out for a long time, and posting here is a last resort.
There are multiple errors in your code
&symbol (where symbol is char[21]) yields char(*)[21], use symbol directly and let it decay to char* or use explicitly &symbol[0]
double weight; is uninitialized local variable, using it results in undefined behavior - you should initialize it: double weight = 0.0;
double w= 0; used to declare a member of class Molecule is invalid, you could use constructor's initializer list:
Molecule() : w(0.0) { } // initializes `w` to `0.0`
s = symbol; where s is char[21] and symbol is char* will not copy strings, for C-style copying strcpy could be used (note that C and C++ are different languages)
you have called new[] so it would be nice and appropriate to call delete[] as well and instead of relying on OS cleaning it up after the program terminates: (otherwise follow the point 6)
Molecule *molecule = new Molecule[n];
...
delete[] molecule;
If you are allowed to use vectors, replace Molecule *molecule = new Molecule[n]; with std::vector<Molecule> molecules(n);
If you are allowed to use std::string1) objects, replace char[21] / char* with std::string objects
Other suggestions:
use meaningful names for variables, if you want to explicitly distinguish private members from other local variables, good convention is to use _ at the end of the name:
class Molecule {
private:
std::string symbol_;
std::string description_;
double weight_;
1) Basically what you need to know about std::string is that it is a template that wraps raw char* and it already contains well-defined copying, concatenation using operator + and most important: you don't need to bother with memory management. Just #include <string>
In the call
molecule[i].set(&symbol,&discription,weight);
you are passing a pointer to a char array. This does not match the char* that set expects.
The easiest/best fix is to change this to
molecule[i].set(symbol,description,weight);
relying on the symbol and description char arrays automatically decaying to pointers.
Alternatively, you could also write
molecule[i].set(&symbol[0],&description[0],weight);
to explicitly pass char*
[Note that there are many other errors in the code posted. Based on the question, I'm guessing they are just typos. Please update your question if you'd like more info onn any of the other errors.]
Okay, this one has me stumped. I am trying to pass an array of character arrays into my class's constructor. The class has a private attribute which stores a pointer to the array of character arrays. The class may then process the array via the pointer.
Below is some code that demonstrates the desired functionality. But, it won't compile. How do I fix this code so it works?
using namespace std;
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char * inArray[][MAX_STRING]) : input(inArray){};
private:
char * input[MAX_LINES][MAX_STRING];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
Alphabetizer theAlaphBet(charArray);
return 0;
}
If you're insisting on using C-compatible character pointers, I think you'll have the best luck using a char ** as the type for input. This is more of the usual way to do this (in C at least), and it has the added benefit of not forcing you to define a maximum string size.
As others have pointed out, you can take advantage of std::string instead, which may be a better choice overall.
I'm guessing it's that you're not passing a pointer to char[][], you're passing a char[][].
Also, you should be using std::string instead of char arrays.
std::string will be the most appropriate here! It handles strings and character arrays well enough!
There are few errors in the code. I suppose you are trying to refer to the charArray in the main function from inside the Alphabetizer object. If that is the case the declaration
char * input[MAX_LINES][MAX_STRING];
is wrong because the above declaration makes input an array of MAX_LINE of ( array of MAX_STRING of (char*)). In summary input is an array not a pointer to array of whatever. If you had intended it to be a pointer - which is what rest of your code hints to me - then you have to do the following,
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char ((*ar)[MAX_LINES])[MAX_STRING]) : m_ar(ar){};
private:
char ((*m_ar)[10])[80];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
char ((*ar)[MAX_LINES])[MAX_STRING] = &charArray;
Alphabetizer theAlaphBet(&charArray);
return 0;
}
Moreover doing,
input(inArray)
is wrong, as it is equivalent to doing the following,
char a[1] = {'a'};
char b[1] = {'p'};
a = b;
assigning an array to another does not copy one over another. You have to do explicit memcpy. (This semantics is not meaningful in c or c++)
It's difficult to tell without seeing the compile errors, but I think the problem might be this line:
Alphabetizer theAlaphBet(charArray);
You are passing the array directly rather than it's address. It should read:
Alphabetizer theAlaphBet( &charArray );
However I think you may be overcomplicating things. You might be better off using a reference rather than a pointer:
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char & inArray[][MAX_STRING]) : input(inArray){};
private:
char & input[MAX_LINES][MAX_STRING];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
Alphabetizer theAlaphBet(charArray);
return 0;
}
You might also want to look into using std::string instead as this may help to simplify your code.