I just discovered reinterpret_cast in C++ and I am trying to learn more about it. I wrote this code:
struct Human{
string name;
char gender;
int age;
Human(string n, char g, int a) : name(n), gender(g), age(a) {}
};
int main()
{
Human h("John", 'M', 26);
char* s = reinterpret_cast<char*>(&h);
Human *hh = reinterpret_cast<Human*>(s);
cout << hh->name << " " << hh->gender << " " << hh->age << endl;
}
It works pretty well, exactly as expected. Now I want convert the char * to an std::string and then from this string get back the Human object:
int main()
{
Human h("John", 'M', 26);
char* s = reinterpret_cast<char*>(&h);
string str = s;
Human *hh = reinterpret_cast<Human*>(&str);
cout << hh->name << " " << hh->gender << " " << hh->age << endl; // prints wrong values
}
Does anyone have an idea to overcome this ?
Thank you.
In your second program when you do
string str = s;
you create a completely new object that is totally unrelated to the pointer s. Getting the address from str will give you a pointer to str, and not the "string" it contains.
Also, using reinterpret_cast is a way to tell the compiler "I know what I am doing", and if you don't actually know what's happening then you will undoubtedly march into the territory of undefined behavior which is what will happen when you try to initialize str with the "string" pointed to by s, since it's not really a string.
Related
Working on an assignment about Abstract Base classes, I'm running into a segment fault when I execute the getInput function I created in the addRecord function. I've tried a variety of methods for getting the user input for the name of the Employee/Student, however I keep running into issues with it.
getInput:
char* getInput(std::string message)
{
char* name;
std::cout << message << std::endl;
std::cin.ignore(INT_MAX, '\n');
std::cin.getline(name, INT_MAX);
return name;
}
addRecord:
/*
* addRecord(vecotr<base*>& v)
*
* Ask the user which type of record they want to add, an employee or student. Once
* they have made their selection, dynamically create a new pointer of the selected
* type of record and have them fill out the record's members via its set methods,
* then add it to the vector using the vector method .push_back().
*/
void addRecord(std::vector<Base*>& v)
{
std::cout << "--Records to Create--" << std::endl;
std::cout << "1.) Student Record" << std::endl;
std::cout << "2.) Employee Record" << std::endl;
std::cout << "Please select from the above options: ";
int sel = intInputLoop(1, 2);
clearConsole();
if (sel == 1)
{
char* name;
/*
std::cout << "Record Type: Student" << std::endl;
std::cin.ignore(INT_MAX, '\n');
std::cin.getline(name, INT_MAX);
*/
name = getInput("What is the Student's name? ");
float gradePointAverage = (float)intInputLoop(0, 4);
Student student = Student();
student.setName(name);
student.setGradePointAverage(gradePointAverage);
Base* bp = &student;
v.push_back(bp);
std::cout << "Added Student record for " << name << " with a grade point average of " << gradePointAverage << std::endl;
delete name;
}
else
{
char* name;
std::cout << "Record Type: Employee" << std::endl;
name = getInput("What is the Employee's name? ");
std::cout << "What is the Employee's salary? ";
int salary = intInputLoop(0, 0);
Employee employee = Employee();
employee.setName(name);
employee.setSalary(salary);
Base* bp = &employee;
v.push_back(bp);
std::cout << "Added Employee record for " << name << " with a salary of " << salary << std::endl;
delete name;
}
}
Any input is much appreciated. Thank you in advance.
char* name;
This declares a pointer, to an indeterminate number of char values. Who knows how many of them there are. It could be just one, very lonely char, sitting there, all by itself with nobody to play with. It could be a million, an entire city of chars. It's completely unspecified, nobody knows; that's because the pointer is completely uninitialized. Nothing in C++ happens automatically. If you intend to use a pointer, it must, well, point somewhere valid before you can use that pointer.
std::cin.getline(name, INT_MAX);
This call to getline reads input into a pointer. The pointer must point to valid memory. Since the pointer is uninitialized, this is undefined behavior, and is the reason for your crash.
Since your intent here is to use C++, the simplest solution is to use a C++ class that just happens to handle all the memory management for you: std::string:
std::string name;
std::getline(std::cin, name);
You'll need to replace all old-fashioned char * pointers, which is what you would use if you were writing C code, with std::string. After all: this is C++, not C.
#include <iostream>
using namespace std;
int main() {
int age = 20;
const char* pDept = "electronics";
cout << age << " " << pDept;
}
The above code is normal.
Why shouldn't I use cout << *pDept instead of cout << pDept above?
Both of them are legal in C++. Which one to use depends on what you want to print.
In your case, pDept is a pointer that points to a char in memory. It also can be used as a char[] terminated with \0. So std::cout << pDept; prints the string the pointer is pointing to.
*pDept is the content that pDept points to, which is the first character of the string. So std::cout << *pDept; prints the first character only.
I'm working on my gematria project that I was asking about before and I managed to fix my main issue there, however I'm trying to break the program down into methods, and I'm getting a error with it and am having trouble figuring out how to fix it.
Here is my current code.
#include<iostream>
#include<unordered_map>
#include<string>
void PrintGematria(){
std::string Gematria = std::string AskGematria()
if(!Gematria.empty()){
std::cout << "The gematria of " << Gematria << " is " << int ConvertLetters(Gematria);
PrintGematria();
}
else {
std::cout << "Hope you enjoyed\n";
}
}
[[maybe_unused]] std::string AskGematria(){
std::cout << "What do you want the gematria of?\n";
std::string Gematria;
std::getline(std::cin, Gematria);
return Gematria;
}
[[maybe_unused] int ConvertLetters(const std::string& Letters){
//Converts letters to numerical value.
std::unordered_map <char, double> Gematria_Values = {
{' ', 0},
{'א', 1},
{'ב', 2},
{'ג', 3},
//Goes through rest of hebrew alphabet.
};
int sum = 0;
for (auto ch : Letters)
sum += Gematria_Values[ch]
return sum;
}
int main() {
//Gives the Value to the user.
PrintGematria();
return 0;
So at the end in my main method when I reference PrintGematria(), it seems to be fine, however in my PrintGematria() method itself I'm getting an error when calling AskGematria() and when calling ConvertLetters(Gematria), it says about both of those methods
Expected '(' for function-style cast or type construction.
The thing is that when I try
void PrintGematria(){
std::string Gematria = std::string (AskGematria());
if(!Gematria.empty()){
std::cout << "The gematria of " << Gematria << " is " << int (ConvertLetters(Gematria));
PrintGematria();
}
else {
std::cout << "Hope you enjoyed\n";
}
I also get a error albiet here it just shows the red and doesn't say what to do there.
So ultimately I want to know how do I properly call the methods in this case?
There are two issues with your function call.
You are attempting to call a function before it has been declared / defined. Either move AskGematria above PrintGematria or add a prototype declaration for AskGematria ahead of PrintGematria:
std::string AskGematria();
The proper way to call the function is std::string Gematria = AskGematria();. You don't need to put std::string before the function call.
I am learning pointer and this is my code. I defined a pointer to char (string actually) *str and a pointer to int *a, they are defined in the same way. I thought both str and a should be an address, but when I tried to output str and &str, a and &a, I found str is not an address, it is the string. What is the difference between char *str and int *a in terms of the type of str and a? Thank you.
#include<iostream>
#include<string>
using namespace std;
int main()
{
char *str = "FA";
cout << "str: " << str << endl;
cout << "&str: " << &str << endl;
int b = 5;
int *a = &b;
cout << "a: " << a << endl;
cout << "&a: " << &a << endl;
}
this is output:
str: FA
&str: 0x7fff5a627280
a: 0x7fff5a62727c
&a: 0x7fff5a627288
Well, this comes down to C semantics. A string is not a type defined in C. char is the type of a single character. In order to handle strings in C, by convention a pointer to char means a string that starts at the position this pointer points to and ends at the first 0 byte.
To make that clear:
char *str = "ABC";
"translates" to something like
const char <nosymbol>[4] = {'A', 'B', 'C', '\0'};
char *str = &(<nosymbol>[0]);
C++ knows about this special meaning of a char * and so, the << operator will, following the principle of least surprise for C programmers, take char * as a string.
The << operator for streams has an overload for char * that outputs a C-style string. This is usually what you want, but if it's not what you want, you can use reinterpret_cast<void*> or addressof.
One of my weaknesses is effectively using chars in C++ which is what I am trying to do right now. I have a player class in my game and within the player class, I create a playerCard object which displays various information. This works fine for a single instance of the player object (i.e. Player player) but when I attempt to push_back a player object in to a vector it all goes wrong.
Basically, the program continues to run but the player doesn't render to the screen. When I quit the program, I then get a breakpoint error when main tries to return MSG. The comment about the breakpoint reads:
/*
* If this ASSERT fails, a bad pointer has been passed in. It may be
* totally bogus, or it may have been allocated from another heap.
* The pointer MUST come from the 'local' heap.
*/
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
I have located the error to here
strcat(nameCard, nameChar);
strcat(nameCard, genderChar);
strcat(nameCard, ageChar);
strcat(nameCard, cashHeldChar);
strcat(nameCard, productWantedChar);
within the playerCard class because when I comment this out, I do not get the error. Here is the full playerCard class (Again, it is messy and probably the wrong way for going about things but I am trying to get my head round using chars/strings etc)
#include "Headers.h";
class Playercard{
private:
RECT textbox;
LPD3DXFONT font;
std::string nameStr;
std::string genderStr;
std::string ageStr;
std::string cashHeldStr;
std::string prodWantedStr;
char nameCard[1000];
public:
Playercard()
{
}
void load(char* name, bool male, int age, double cash, char* prod)
{
if(male)
{
genderStr = "Gender: Male\n";
}
else
{
genderStr = "Gender: Female\n";
}
nameStr = "Name: " + static_cast<std::ostringstream*>( &(std::ostringstream() << name))->str() + "\n";
ageStr = "Age: " + static_cast<std::ostringstream*>( &(std::ostringstream() << age))->str() + "\n";
cashHeldStr = "Cash Held: " + static_cast<std::ostringstream*>( &(std::ostringstream() << cash))->str() + "\n";
prodWantedStr = "Product Wanted: " + static_cast<std::ostringstream*>( &(std::ostringstream() << prod))->str() + "\n";
char * nameChar = new char [nameStr.length()+1];
char * genderChar = new char [genderStr.length()+1];
char * ageChar = new char [ageStr.length()+1];
char * cashHeldChar = new char [cashHeldStr.length()+1];
char * productWantedChar = new char [prodWantedStr.length()+1];
strcpy(nameChar, nameStr.c_str());
strcpy(genderChar, genderStr.c_str());
strcpy(ageChar, ageStr.c_str());
strcpy(cashHeldChar, cashHeldStr.c_str());
strcpy(productWantedChar, prodWantedStr.c_str());
strcat(nameCard, nameChar);
strcat(nameCard, genderChar);
strcat(nameCard, ageChar);
strcat(nameCard, cashHeldChar);
strcat(nameCard, productWantedChar);
diagFile.open("Diag.txt");
diagFile.write("Test", 100);
diagFile.close();
}
void setUp(int L, int T, int R, int B)
{
SetRect(&textbox, L,T,R,B);
}
void draw()
{
font->DrawTextA(d3dSprite, nameCard, -1, &textbox, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));
}
LPCSTR plCard()
{
return nameCard;
}
};
Any help would be greatly appreciated. Thank you.
Your nameCard is uninitialized. Replace the first strcat with strcpy, or initialize it with a zero string.
Now, how about using std::string exclusively?
Your main problem is that nameCard is uninitialized. strcat requires a null-terminated string to do its magic, and there's no guarantee that the first, or any, character in nameCard is a null.
However, C strings are unnecessary. Just use std::string all the time. After changing nameCard to a string, I'd change load to (file writing excluded):
void load(const std::string &name, bool male, int age, double cash, const std::string &prod)
{
nameStr = "Name: " + name + "\n";
genderStr = "Gender: " + (male ? "Male" : "Female") + "\n";
ageStr = "Age: " + std::to_string(age) + "\n";
cashHeldStr = "Cash Held: " + std::to_string(cash) + "\n";
prodWantedStr = "Product Wanted: " + prod + "\n";
nameCard = nameStr + genderStr + ageStr + cashHeldStr + prodWantedStr;
}
I would actually just make nameCard a data member, removing the others, and use this:
nameCard.clear();
nameCard += "Name: " + name + "\n";
//add on other parts
Other than that, make plCard() return a std::string and in draw(), use nameCard.c_str(). I hope that clears up what you can do with strings a bit more.
Do note, however, that std::to_string is C++11. C++03 has two common solutions:
std::string str = boost::lexical_cast<std::string>(someNumber);
Or
std::ostringstream oss;
oss << someNumber;
std::string str = oss.str();
I find the three-liner much more readable than a one-liner or two-liner.