It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
So, I'm reading Schildt's book 3rd edition about C++ and I'm doing all examples, but I have some PHP background and when I tried some stuff it occurs that it can not be compiled this way.I saw the Schildt's solution, so I'll give what I've tried to do and how it's done in the book, what I need to know, is there any way to make it work adjusting my function?
Here's what I'm trying
class card {
char author[40];
//char book[30];
int count;
public:
void store(char *auth,int ct);
void show();
};
void card::store(char *auth,int ct){
&author = *auth;
count = ct;
}
int main(){
card ob1, ob2;
ob1.store('Tolkin',10);
ob2.store('Pratchet',3);
ob1.show();
ob2.show();
return 0;
}
And here's the Schildt's solution:
class card {
char author[40];
int count;
public:
void store(char *auth,int ct);
void show();
};
void card::store(char *auth,int ct){
strcpy(author, auth);
count = ct;
}
The quick fixes:
Instead of char author[40] use std::string.
store(const std::string& auth,int ct)
author = auth; (std::string has assignment operators)
ob1.store("Tolkin",10); (single quotes are for char-literals)
Give card::show() a body. You currently have just the declaration. And because show() does not mutate card, make it a const member function: void show() const;
The real fix (sounds lapidar, but is my serious, well-intentioned advice):
Get a good introduction to C++.
I think the basic misunderstanding here is the way that C/C++ handle "char arrays" as strings. The strcpy routine copies the contents of a string, where the = assignment operator (applied to char) copies a single character, or a pointer to the string. &author = *auth will look at the auth pointer, dereference it using *, and take the single char found there, then take the address of (&) your char[] named author, and try to change the address to the char value.
You could…
Use strcpy to copy the contents of the string (but, in new code, don't use strcpy, use strncpy instead!)
Store a pointer to the string provided (char* author in your class would be assigned as author = auth; but then, if auth is free()d or delete[]()ed later, you will have a pointer to memory that no longer contains your string, which is bad)
Use a C++ std::string object instead of a C-style char[] for your string, which will behave more like a PHP string would. std::string author could be copied from std::string auth using author = auth.
String-handling in C++ is a big subject, but you will definitely want to get a good understanding of the differences between "thing" and "pointer-to-thing" types … !
Also, in C++, you must use "" around strings, and '' around single chars. There is a lot less "magic" in a C/C++ "" string, though; only \x type escape sequences work (for example, there is no "$var" substitution available). In Perl/PHP/Bourne/... you use '' for non-escaped strings and "" for escaped strings; in C++, since char and char[]/std::string are different types, they use the punctuation differently.
Not really, no. For any given instance of card, author is stored at a specific, fixed, memory location relative to the rest of the object. (author is actually inside the object: if you do std::cout << sizeof(card) << std::endl; you'll see that card is 40 bytes, because all it contains is an array of forty characters.) &author = ... is trying to tell the compiler that author is now stored somewhere else, but there's no way to tell the compiler that, because you already promised that author is stored inside the card.
That said, you could change your declaration of author to be a true pointer, rather than an array:
char * author;
and then assign to it like so :
author = auth;
but that's not a good idea. Whenever you pass a pointer around, you have to keep track of where it's gone, to make sure that all of your pointers are always valid, and that you never lose a pointer to memory you need to de-allocate later.
you are mixing up some types:
PHP is not typed while c++ is.
you can t compile because you are trying to assign a pointer to a reference.
&author = *auth;
i suggest to read a lot of documentation about reference and pointers!!
cheers!
Related
I'm learning to code c++ and I've come to this problem:
I have this struct:
struct storeData
{
string name;
string username;
string fav_food;
string fav_color;
}data[30];
And I need to check if two usernames are equal so I made this statement:
for(i=0;i<c;i++){
if(data[c].username.compare(data[i].username)==0){
cout<<"Username already taken"<<endl;
}
}
And it works well, the problem that I have is that I'm required to make a function let's call it: isTaken that returns the error message, so I can use it whenever I need to for example delete a username so I don't have to copy/paste the code again.
So I began looking for an answer for that, many forums present a way to send the whole struct like this:
void isTaken(struct storeData *data)
which I understand but because I'm using string is not working, so I guess it's because string is an object? I'm using the library <string> I'm sorry if I'm not being that clear at the moment, I'm looking for a way to use isTaken(data[c].user); but I don't know how to declare the function, I think is also because string is not the same as C string but I'm not really sure I've been looking for a solution and could not find it.
I tried: void isTaken(struct storeData *data) but I got an error saying that I can't convert std::string to basic_string which makes sense if I'm correct about string I tried converting string into c string but could not get anywhere. I'm open to suggestions/corrections because I want to improve my code, also I could not find the answer here, so If someone's got a link to a problem like this please let me know.
Thank you so much for you time, have a good day.
Do you mean an array of structs instead of a struct of arrays?
In the example you are giving I see only an array of structs each of which has multiple string objects in it. You see, a string is a class coming from std and I wouldn't call it an array. If you want to know how to pass an array to a function, you should read about it (I'm sure you can find such a question in SO). If you want to have an array within your struct, then the struct will take care of the memory of the array, but you should definitely read about constructors.
You got an error because you are passing an string argument to a function which requires struct pointer
void isTaken(struct storeData *data);
...
isTaken(data[c].user);
but what you actually need is to have a function which takes an array of your users, its size and username you want to check
bool IsUsernameTaken(struct storeData data[], int dataSize, const string &username){
for(int i = 0; i<dataSize; i++){
if(username == data[i].username)
return true;
}
return false;
}
A C string looks like this
data
A C++ string usually looks like this
size
capacity
ptr
|
v
data
or if using short string optimization and the string is short enough
size
data
data
all are zero terminated.
Making a shallow copy a C string only cost the copy of the pointer to it. Where a copy of a might cost just copying the 3 members and possible an allocation of data, which is not ideal, therefor most C++ functions use a reference to a string making the cost equivalent to the C string.
All code is untested.
bool Find(const std::string& target);
Making a deep copy of a C string would also cost an allocation.
In C++ you have many options to do a search, for your struct it could look like this. In case your member variables are private you must use an access function
auto found = std::find(std::begin(data), std::begin(data)+c, [&target](const storeData& auser) { return auser.GetName() == target });
return (found != std::begin(data)+c);
The first two parameters are the range that is search, not including the 2nd. A lambda is used to check the name, a free function with the right declaration would also do.
std::string& GetName() { return name; }
The higher C++ protection schemes would advice adding 2 consts to that in case you don't need to change name.
const std::string& GetName() const { return name; }
Meaning the returned string cant be changed and the 2nd says it wont change anything in your class. This const version would be required as I used a const storeData& auser in the lambda to satisfy the constness of the struct.
I am working on a project where a question is displayed in a game window.
Since this question will need to change a lot, I figure it would be easier to have 5 defined lines of text (1 for question, 4 for MC answers) that are simply edited every time the question changes.
I have tried this in the header file:
struct tagQuestion{
int x, y;
const char* qLine[150];
char ansA[150];
char ansB[150];
char ansC[150];
char ansD[150];
}question[1];
then in my main.cpp
question.qLine[150] = "TEST PHRASE";
but it is returning the error "qLine" in "question", which is of non-class type "tagQuestion[1]"
I have tried both char and const char* to no success.
I am trying to follow an example in my textbook and I think I'm misunderstanding it.
Once I declare the character array in the header file, can't I edit its contents in the main file?
That [1] after question doesn't seem to be making any sense. Remove it.
Your answers are arrays of char, but your question is an array of char pointers. I am pretty sure you don't want your question to consist of 150 char pointers.
If you want to change qLine, don't make it const.
qLine[150] = ... This assigns a value to the 151st element of an array with 150 elements. Neither what you want, nor legal code. You probably want qLine =, but that doesn't work with an array, instead you need to use a function like strcpy that writes data into the array, but I highly advise against that. (see next point)
Don't do C in C++. Use std::string, not arrays of char.
If you have strings that regularly change, create a file where your strings are stored, load them into a map, and pull them from the map wherever and whenever you need them, instead of putting hardcoded strings in your code. That way you don't need to change any code, when you change text.
I suggest something like this:
struct Question {
std::string text;
std::vector<std::string> answers;
};
std::map<std::string, Question> questions;
And then something like this:
ifstream questionsFile("questions.txt");
if (questionsFile.is_open())
{
std::string line;
while (std::getline(questionsFile, line))
{
// Split line into some id, text and answers, how exactly depends on the format you chose
std::string id = ...;
Question question;
question.text = ...;
question.answers.push_back(...);
questions[id] = question;
}
questionsFile.close();
}
else
{
// Handle error
}
And wherever in your code:
// Print question with id "q1":
std::cout << questions["q1"].text << std::endl;
// Print answer #2 for question with id "q1":
std::cout << questions["q1"].answers[1] << std::endl;
Even better would be to make Question a class that hides its internals and has accessor methods and a constructor or static method to create new instances from valid lines with proper error handling.
happy coders!
I had a plan to try to learn some C++ today and so I thought I could take an old C assignment from a previous course and just do the same thing in C++. The assignment is to read music files and retrieve data from their ID3 tags and sort them in folders according to their artist, album and track title etc etc... this does not really matter but you know at least what I'm going for.
So I played around a little with sets and made my program receive an array of strings specifying different songs which it will loop the algorithm over.
In this next step I got stuck though due to how I tried to copy the behaviour of my old C program which was a struct containing three values being:
int size;
char *tag_name;
char *data;
but so far I have been unable to recreate this dynamic behaviour in C++ where I wish to only have the members defined but not initialised since I wanted to be able to change this data later on. Technically I can do this in a way where I get the data from the file before I create the tag, and therefore give the constructor their initial values and be done with it. But can I do it in the way I want to?
class Tag {
public:
std::string name;
std::string data;
int size;
Tag() {}
Tag(std::string n, std::string d, int s) : name(n), data(d), size(s) { }
void setData(std::string data) { this.data = data }
};
Since I've tried a billion combinations of pointers and whatnot (Googled loads) I just returned to the above and decided to ask you how to actually accomplish this.
My brained is completely mashed but consider the above psuedo code since I bet it is not correct in any way...
So my question is:
How do I define a class so that I get a dynamic string allocation for the members name and data? I was almost thinking of using some good old char* but the point of me trying this was to learn some C++, so I am forcing myself to go through this now.
If I understand your question correctly, your default constructor already takes care of this. Your std::strings will initialize to empty string "". You can assign a different value to
this string at any time.
If you really wanted to, you could change your default constructor to
Tag() : name(""), data(""), size(0) {}
Ps: This is more of a conceptual question.
I know this makes things more complicated for no good reason, but here is what I'm wondering. If I'm not mistaken, a const char* "like this" in c++ is pointing to l and will be automatically zero terminated on compile time. I believe it is creating a temporary variable const char* to hold it, unless it is keeping track of the offset using a byte variable (I didn't check the disassembly). My question is, how would you if even possible, add characters to this string without having to call functions or instantiating strings?
Example (This is wrong, just so you can visualize what I meant):
"Like thi" + 's';
The closest thing I came up with was to store it to a const char* with enough spaces and change the other characters.
Example:
char str[9];
strcpy(str, "Like thi")
str[8] = 's';
Clarification:
Down vote: This question does not show any research effort; it is unclear or not useful
Ok, so the question has been highly down voted. There wasn't much reasoning on which of these my question was lacking on, so I'll try to improve all of those qualities.
My question was more so I could have a better understanding of what goes on when you simply create a string "like this" without storing the address of that string in a const char* I also wanted to know if it was possible to concatenate/change the content of that string without using functions like strcat() and without using the overloaded operator + from the class string. I'm aware this is not exactly useful for dealing with strings in C++, but I was curious whether or not there was a way besides the standard ways for doing so.
string example = "Like thi" + "s"; //I'm aware of the string class and its member functions
const char* example2 = "Like this"; //I'm also aware of C-type Strings (CString as well)
It is also possible that not having English as my native language made things even worst, I apologize for the confusion.
Instead of using a plain char string, you should use the string library provided by the C++ library:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str = "Like thi";
cout << str << endl;
str = str + "s";
cout << str << endl;
return 0;
}
Normally, it's not possible to simply concatenate plain char * strings in C or C++, because they are merely pointers to arrays of characters. There's almost no reason you should be using a bare character array in C++ if you intend on doing any string manipulations within your own code.
Even if you need access to the C representation (e.g. for an external library) you can use string::c_str().
First, there is nothing null terminated, but the zero terminated. All char* strings in C end with '\0'.
When you in code do something like this:
char *name="Daniel";
compiler will generate a string that has a contents:
Daniel\0
and will initialize name pointer to point at it at a certain time during program execution depending on the variable context (member, static, ...).
Appending ANYTHING to the name won't work as you expect, since memory pointed to by name isn't changeable, and you'll probably get either access violation error or will overwrite something else.
Having
const char* copyOfTheName = name;
won't create a copy of the string in question, it will only have copyOfTheName point to the original string, so having
copyOfTheName[6]='A';
will be exactly as
name[6]='A';
and will only cause problems to you.
Use std::strcat instead. And please, do some investigating how the basic string operations work in C.
Ok, this is for homework about hashtables, but this is the simple stuff I thought I was able to do from earlier classes, and I'm tearing my hair out. The professor is not being responsive enough, so I thought I'd try here.
We have a hashtable of stock objects.The stock objects are created like so:
stock("IBM", "International Business Machines", 2573, date(date::MAY, 23, 1967))
my constructor looks like:
stock::stock(char const * const symbol, char const * const name, int sharePrice, date priceDate): m_symbol(NULL), m_name(NULL), sharePrice(sharePrice), dateOfPrice(priceDate)
{
setSymbol(symbol);
setName(name);
}
and setSymbol looks like this: (setName is indentical):
void stock::setSymbol(const char* symbol)
{
if (m_symbol)
delete [] m_symbol;
m_symbol = new char[strlen(symbol)+1];
strcpy(m_symbol,symbol);
}
and it refuses to allocate on the line
m_symbol = new char[strlen(symbol)+1];
with a std::bad_alloc. name and symbol are declared
char * m_name;
char * m_symbol;
It's definitely strlen() that is going astray. And it doesn't seem to happen every time.
cout << symbol << strlen(symbol);
returns IBM correctly, then crashes
As this is tagged C++ can you use std::string instead of doing all the pointer maintenance yourself on char*?
std::string name;
std::string symbol
Then setSymbol becomes easy:
void stock::setSymbol(const char* symbol)
{
this->symbol = symbol;
}
There must be some problem with symbol parameter at the time you call
new char[strlen(symbol)+1];
and strlen return a huge length that C++ runtime is unable to allocate. If symbol is uninitialized char* pointer at the beginning this is fairly possible. It doesn't fail all the time, does it?
I was able to run the code without problems on Cygwin, so I'd guess it's something implementation-dependent in distinguishing the parameter symbol from the member symbol.
You say yourself that it's confusing -- well do something about it!!! And may I suggest, never, ever again, naming a parameter the same as a local/member variable. (Not only does it eliminate confusion, you won't need to disambiguate the member variable with this->.)
Thanks to everyone who offered help. I went over it with my professor, and unfortunately I was overflowing an array earlier and corrupting the heap, which was manifesting itself here.
This was a good conversation for me though. It helped me think through some things I had just been doing. So thanks again SO'ers