Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to create a constructor that sets an array field to null.
Im getting a "no viable overloaded '=' " error
Horse::Horse()
{
string *ptr;
ptr = NULL;
Name[SIZE] = ptr;
}
My question is what exactly is going on behind the scenes here. I thought I could create a string pointer, set it to null, then set the array to the pointer and it would make the first element of the array equal to null?
Thanks
Setting Name[SIZE] to point to the address of std::string * is meaningless.
If Name is a std::string array, then the array will be defaulted empty.
If your task was to set the Name field empty in the constructor, I'm going to assume this is a const char* instead of a std::string. This can be done using initializer list:
Horse::Horse()
: Name{0} // Name{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} does the same thing.
{} // empty body
The above will initialize all the 20 positions to 0, or NULL if you like. Just as if you declared it in the global scope.
If you are not familiar with the initializer list in constructors, you can always do this, but at an extra cost:
Horse::Horse() // Initialize members runs first
{
for (int i = 0; i != SIZE; ++i) // Assign values to Name array
Name[i] = 0;
}
Side note: Instead of using macros to define your values, a better choice is to use const unsigned SIZE = 20; for reasons described here
I'll just go ahead and write the whole thing for you.
If you think about what a name is, it's just a string, a string of characters. So Name should be a std::string. Then the constructor would look like this:
Horse::Horse() {}
Done. Name will be initialized to an empty string, i.e. "".
If the assignment requires you to use C-strings (char arrays) instead of std::string, then Name should be of type char*, if it needs to be set to NULL. Now the constructor would look like this:
Horse::Horse() : Name(NULL) {}
The Name field will be initialized to NULL, i.e. it will be a null pointer, hence it doesn't contain even an empty string.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Ok I have used C for 3 years.
My major is embedded system Engineering
I have had an interest in image processing just a few days ago.
So I am studying C++.
I want to change last character when I use copy constructor.
like these -> Cannon1 Cannon2 Cannon3 (Cannon is just name)
So I used pointer with While as I do in C.
Photon_Cannon::Photon_Cannon(int x, int y, char *cannon_name)
{
int i = 0;
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
name = new char[strlen(cannon_name) + 1];
strcpy(name, cannon_name);
}
this is original code (this works normally)
and I attached some codes end of the section of copy constructor.
while (*name!=NULL) {
name++;
}
*name+=1;
but it doesn't work! :(
help me...
Try to use std::string instead of char*.
Photon_Cannon::Photon_Cannon(int x, int y, const std::string& cannon_name)
Change member variable name to std::string aswell, then you can easily assign string's like
name = cannon_name;
And then change last character
name[name.length() - 1] = '2';
Or
name.pop_back();
name += "2";
Don't forget to include string.
Or with char*
name[strlen(name) - 1] = '2';
Dont forget to check size of array/string, name.length() > 0), (int)strlen(name) > 1, ...
I would recommend you to read some c++ tutorial's like
C++ strings.
Iam new on stackoverflow, so i hope it helped you :).
This is not intended as answer, just as a side note to Filip's already given answer (and the comments there):
void f(std::string const& s)
This is the usual way to pass std::string objects, because it avoids creating unnecessary copies of (costing runtime and memory). If you actually want to modify the string (changes will be visible to the string object passed to f), leave away the const modifier.
Now here we have a special case:
void f(std::string const& s)
{
std::string ss(s); // creates a COPY!
// modify the copy ss...
}
Obviously, the copy is to be modified, but changes shall not be visible to the original string object passed to. If we don't need access to the original string any more (s), then and only then, it makes sense to pass the string by value:
void f(std::string /*const&*/ s) // creates the COPY already when passing
{
/* std::string ss(s); // creates a COPY! */ // <- don't need it any more
// modify the COPY s now...
}
Side note: Really leaving the const reference as comment as above (/*const&*/) would express (and should suffice for) that passing by value was done intentionally...
This question already has answers here:
What is the function of an asterisk before a function name?
(4 answers)
Closed 6 years ago.
I am fairly new to C++ and I am trying to decode the piece of code shown below. In particular for the BaseSetAssoc::BlkType* line, I am not sure what the asterisk means in this case. I would appreciate some insight.
BaseSetAssoc::BlkType*
NMRU::accessBlock(Addr addr, bool is_secure, Cycles &lat, int master_id)
{
// Accesses are based on parent class, no need to do anything special
BlkType *blk = BaseSetAssoc::accessBlock(addr, is_secure, lat, master_id);
if (blk != NULL) {
// move this block to head of the MRU list
sets[blk->set].moveToHead(blk);
DPRINTF(CacheRepl, "set %x: moving blk %x (%s) to MRU\n",
blk->set, regenerateBlkAddr(blk->tag, blk->set),
is_secure ? "s" : "ns");
}
return blk;
}
BlkType isn't a member function, it's a type, possibly an enum or struct if not an inner class.
The BaseSetAssoc:: is needed to access such "inner" types (defined within a class, i.e. BaseSetAssoc).
So BaseSetAssoc::BlkType* is just a BaseSetAssoc::BlkType pointer.
It's not "following", it's "preceding". As the comments have said: it means that it is returning a pointer to BaseSetAssoc::BlkType, rather than a whole BaseSetAssoc::BlkType.
What does this mean? It means mostly that the pointer can be NULL, or non-existent. Before using the result of this function, it is almost mandatory that you check if it is NULL first.
Is this typecasting in C++ or am I seeing things?
((YesNoQuestion*)first)->setAnswer(false);
((MultipleAnswerQuestion*)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion*)second)->setCorrectAlternative(2);
And why is this done instead of just
first->setAnswer(false);
second->setAlternative(2, "City2");
second->setCorrectAlternative(2);
or
((YesNoQuestion)first)->setAnswer(false);
((MultipleAnswerQuestion)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion)second)->setCorrectAlternative(2);
Doesn't the pointer provide the sufficient "identity" to make member functions of a child class viable for the parent class?
And why make the types pointers as well? Is it because the Question-objects are pointers that the new type has to be a pointer too?
Context:
These are answers from an old exam 5-6 years ago and everyone is on vacation now so I can't ask the professors who made it, but they did this in the main-file:
#include "MultipleAnswerQuestion.h"
#include "YesNoQuestion.h"
int main()
{
Question *first = NULL;
Question *second = NULL;
string alt[] = {"City1", "City2", "City3"};
first = new YesNoQuestion("Some statement here");
second = new MultipleAnswerQuestion("Some question here", alt, 3, 0);
((YesNoQuestion*)first)->setAnswer(false);
((MultipleAnswerQuestion*)second)->setAlternative(2, "City2");
((MultipleAnswerQuestion*)second)->setCorrectAlternative(2);
first->print(); //Prints Q
second->print(); //Prints Q
}
Abstract baseclass: Question(string question = "");
Children:
YesNoQuestion(string question = "", bool answer = true);
MultipleAnswerQuestion(string question, string alternatives[],
int nrOfAlternatives, int correctAnswer);
This depends on exactly how your classes are defined, but I'm guessing that your Question class does not have a setAnswer method that takes a bool. And since first is a Question pointer, and not a YesOrNoQuestion pointer, then you can't call YesOrNoQuestion methods on it.
The fact that first actually points to a YesOrNoQuestion object is irrelevant, since the compiler must be able to determine at compile time whether a call is valid purely based on the type of the variable.
In your example, you can simply make first be a YesOrNoQuestion pointer to avoid the casting. In more complex situations, it may not be that simple.
This is a type of type casting used for polymorphism. The first alternative you proposed would only work if the base class Question has virtual methods for setAnswer, setAlternative and setCorrectAlternative. If not, then you'd have to convert the pointer to the good class in order for the method to be found. The second alternative would not work because first and second are pointers, therefore their values are an addresses. Interpreting those addresses as objects of a class would not make sense in itself.
(Type*) is often know as C-style casting, this basically choose one from: const_cast, static_cast, reinterpret_cast. I don't like the last one, so I would use one of them.
The reason the cast is done, is most likely because Question doesn't contain the methods which are being called. Why would a generic Question have a setAnswer() which accepts a bool?
In this case, I would have written something like the following:
YesNoQuestion *firstTyped = new YesNoQuestion("Some statement here");
MultipleAnswerQuestion *secondTyped = new MultipleAnswerQuestion("Some question here", alt, 3, 0);
Question *firstUntyped = firstTyped;
Question *secondUntyped = secondTyped;
firstTyped->setAnswer(false);
secondTyped->setAlternative(2, "City2");
secondTyped->setCorrectAlternative(2);
firstUntyped->print(); //Prints Q
secondUntyped->print(); //Prints Q
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I wanted to create an array of a specific size using a variable, but allegedly the only way to do that is to use pointers.
int size = 5;
string* myArray = new string[size];
I now want to assign an element from this array to another variable, which I believe will only work through dereferencing. The following line of code doesn't work. How do I fix it?
string line;
myArray[0] = "Hello";
line = *myArray[0];
Edit:
I just want to clarify something: Using the normal "myArray[0]" code doesn't work either. It compiles, but causes a crash. Here's some more specific code regarding what I want to do.
void MyClass::setLine(string line)
{
myLine = line; /*This is a private variable in MyClass*/
}
///////////////
MyClass* elements = new MyClass[size];
elements[0].setLine(myArray[0]);
I want to assign the array element to a private variable from a class, but the program crashes when I try to assign the value to the private variable.
If you know the size at compile time, you can use a normal array. If you only know the size at runtime, you could still use a std::vector, which is far easier to use than manual allocation.
Anyway, if you really want to learn about pointers for array managing, keep in mind that the index operator is equivalent to addition and dereference, i.e. ar[i] is the same as *(ar + i). In other words, indexing is just dereferencing at an offset.
As such, no extra dereference is needed. Just drop the asterisk in the failing line.
Valid code will look like
string line;
myArray[0] = "Hello";
line = myArray[0];
By the way you could use class std::vector instead of the array if you are going to add or remove elements from the collection.
For example
std::vector<std::string> myArray;
myArrray.reserve( 5 );
myArray.push_back( "Hello" );
line = myArray[0];
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Why this fragment of code does not work? I know that all entered strings have length less than 20 symbols.I do not use std::string because I want to learn how to use char*
#include <map>
#include <stdio.h>
using namespace std;
map <char*,int> cnt;
int main()
{
char ans[20];
int n,mx = 0;
scanf("%d\n",&n);
for ( int i = 1; i <= n; i++){
char str[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
}
Let's be clear that your code has a lot of undefined behavior. I tried running your code and here is what I saw on my machine. You should tell us what your behavior was though because it's impossible to say what's going on for you otherwise.
First off, here was my program input.
3
hello
world
cat
And the output...
cat
char str[20] is a memory address, and that address is being reused by the compiler. Let's say that memory address is 0xABCD.
So on the first iteration, the map contains one element which is { 0xABCD, 1 }. On the second iteration it contains the same element with its value incremented, {0xABCD, 2}. On the third iteration it contains {0xABCD, 3}. Then when you go to print the map, it finds only one element in the map, and prints that memory address. This memory address happens to contain the word "cat", so it prints cat.
But this behavior is not reliable. The array char str[20] doesn't exist outside of the for loop, so sticking it into map <char *, int> cnt and even worse printing the array outside the loop are both undefined behavior.
If you want your code to work, I suppose you could do this....
for ( int i = 1; i <= n; i++){
char * str = new char[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
delete[](i->first);
But really, the correct strategy here is to either....
1) Use std::string
or
2) Don't use std::map
If you want to use C strings beyond converting them to std::string, then program without the use of the C++ std library. Stick to the C standard library.
Seems like cnt is std::map<char*, ...>. When you do cnt[str] you use pointer to local variable str as key, but str is only valid during single iteration. After that str is freed (semantically, optimizer may reuse it, but it is irrelevant here) and pointer to it is no longer valid.
It's very simple: when you allocate a C-style array as a local variable (char str[20];), it is allocated on the stack. It behaves just like any other object that you allocate as a local variable. And when it falls out of scope, it will be destroyed.
When you try to pass the array to the map in cnt[str], the array name decays to a pointer to the first element (it implicitely converts an expression of type char[20] into an expression of type char*). This is something radically different than an array. The map only ever sees this single pointer and stores it as the key. The map does not dereference the pointer to find out what's behind it, it just uses the memory location.
To fix your code, you need to do two things:
You need to allocate memory for your strings on the heap, so that the char* remains valid after the end of the scope. The easiest way to do this is to use the getline() or getdelim() functions available in the POSIX-2008 standard: These beautiful two functions will actually do the malloc() call for you. However, you still need to remember to free the string afterwards.
Making the map aware that you are talking about strings and not about memory addresses is much harder to achieve. If you must use a map, you likely need to define your own std::string-like wrapper class. But I guess, since you are playing around with the char* to learn their use, it would be more prudent to use some other kind of list and program the logic to check whether the given string is already in the list. Could be an array of char*, probably sorted to save lookup time, or a linked list, or whatever you like. For ease, you can just use an std::vector<char*>, but don't forget to free your strings before letting the vector fall out of scope.