Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I'm writing a student administration program right now. I would like to do without strings and libraries to learn how to use pointers. Each student has a name, a number and several courses. I manage this data of the student in a class. Names and courses should only occupy as much space as is absolutely necessary. However, I do not know exactly how to initialize them correctly and create the constructors, setters or getters. Later, I want to manage the Student class in a class with an array of students.
I've already tried managing the char array of courses in an additional array. I did not succeed. That's why I've created a two-dimensional array now. I also came up with the idea to create extra classes for the courses and the array of courses. But that's not how I learn how to handle pointers.
student.h:
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
class Student{
private:
int myLength_name;
char *myName; //=new char[myLength_name];
int myMatrikel;
int myLength_lv;
char *myLv; //=new char[myLength_lv];
//char **myLvs[30];
int myAnzLv;
public:
Student();
Student(char *name_chars, int length_name, int matrikel, int length_lv, char **lv_chars[][30]);
char &name_chars() const { return *myName; }
int matrikel() const { return myMatrikel; }
int length_name() const { return myLength_name; }
int length_lv() const { return myLength_lv; }
char &lv_chars() const { return *myLv; }
};
#endif // STUDENT_H
student.cpp:
Student::Student() :
myLength_name(0),
myName(nullptr),
myMatrikel(0),
myLength_lv(0),
myLv(nullptr),
myAnzLv(0)
{}
Student::Student(char *name_chars, int length_name, int matrikel, int length_lv, char *lv_chars[][30]):
myLength_name(length_name),
myName(name_chars=new char[myLength_name]),
myMatrikel(matrikel),
myLength_lv(length_lv),
myLv(lv_chars=new char[myLength_lv][30]),
{}
Can someone please help me create the class student error free? I'm really not very good with pointers and have not found helpful manuals so far.
Thanks in advance.
Eric
#MPops
Thank you very much for your help. I hope I implemented your code right. The two files now look like this and they don't produce errors:
student.h:
class Student{
private:
char *myName;
int myMatrikel;
char *myLv; //=new char[myLength_lv];
char * * myLvs = new char*[30];
int myAnzLv;
public:
Student();
Student(char *name_chars, int matrikel, char *lv_chars);
char name_chars() const { return *myName; }
int matrikel() const { return myMatrikel; }
char lv_chars() const { return *myLv; }
};
student.cpp:
Student::Student() :
myName(nullptr),
myMatrikel(0),
myLv(nullptr),
myLvs(nullptr),
myAnzLv(0)
{}
Student::Student(char *name_chars, int matrikel, char *lv_chars):
myMatrikel(matrikel)
{
myName = new char[strlen(name_chars)+1];
strcpy(myName, name_chars);
myLv = new char[strlen(lv_chars)+1];
strcpy(myLv, lv_chars);
}
````
When creating a class that has a char pointer (to be used as a dynamic char array), I don't believe you will be able to use the initialization list feature of the constructor. You should first verify that it works simply by...
myName = new char[strlen(name_chars)+1];
strcpy(myName, name_chars);
This is the most basic way to do this. It's not particularly safe though, if for some reason the data doesn't come in correctly (no \0 character in name_chars). But this is a start.
I would also look into strncpy.
To make an ARRAY of dynamic char arrays...
like ["math", "language", "writing", "history"]...
You need an array of dynamic char arrays.
char * course = new char[100]; // this is one char array of length 100.
char * * courses = new char*[10]; // this is 10 char pointers
courses[0] = new char[100]; // now, the first char pointer in courses
// is a dynamic array of length 100.
...
courses[9] = new char[100];
courses[10] = new char[100]; //!!!! THIS IS WRONG. Courses doesn't have 11 items in it.
// you can only use indexes 0-9 (10 char pointers)
Related
I am new to C++. I have an exercise about constructor with const char* parameter.
class Book
{
private:
char* title;
}
public:
Book (const char* title)
{
this->title = title;
}
When I code the constructor like that, I receive error cannot convert const char to char*.
I tried using
strcpy(this->title, title);
then, it run, but I don't get the expected result.
Can anyone help me.
Thank you very much.
You are doing an exercise, did the course you are following not explain what you are supposed to do?
I would guess that this is an exercise in dynamic memory allocation and what you are expected to do is use strcpy after you have allocated some memory so that you have somewhere to copy the string to. Like this
this->title = new char[strlen(title) + 1];
strcpy(this->title, title);
You need to allocate one extra char because C style strings are terminated with an additional nul byte.
But any C++ programmer who was doing this for real (instead of it being a learning exercise) would use a std::string as paxdiablo says.
C++ doesn't let you easily change a const char * into a char * since the latter has no restrictions on how you can change the data behind that pointer.
If you're doing C++, you should be avoiding char * (legacy C) strings as much as possible. By all means take them as parameters if you must, but you should be turning them into C++ strings at the earliest opportunity:
class Book {
private:
std::string m_title;
public:
Book (const char *title) {
m_title = title;
}
};
The one thing you don't want to become is a C+ developer, that strange breed that never quite made the leap from C across to the C++ way of thinking :-)
And, actually, if a given book is never expected to change its title, you're better off making it constant and initialising it, rather than assigning to it, something like:
#include <iostream>
#include <string>
class Book {
public:
Book (const char* title): m_title(title) {};
void Dump() { std::cout << m_title << "\n"; }
private:
const std::string m_title;
};
int main() {
Book xyzzy("plugh");
xyzzy.Dump();
}
I made hospital class and patient class, so what I am trying to do is to make Patient[] patients < this. However, there is showing some error error: expected unqualified-id before '[' token
I do not know what it is wrong with that.
Thank you for your response.
class Hospital
{
public:
Hospital();
void determinePatientType();
protected:
private:
Patient[] patients;
char * fileName;
int patientCapacity;
char * hospitalName;
int totalPatients;
};
1- That is not how to declare an array:
Patient[] patients;
You must make the subscript operator after the identifier not before it.
Patient patients[size];
2- You have to specify array size at compile time so:
patient pat[size];
The size must be constant at compile time. If you want a dynamic size then consider using dynamic arrays. Also i recommend using class vector.
To use a dynamic array you should use pointesrs:
patient* patients;
And layer on you can allocate it:
patients = new patient[size];
Your class could look like:
nclude
using namespace std;
class Hospital{
public:
Hospital(int); // constructor
~Hospital(); // destructor
Hospital();
void determinePatientType();
private:
Patient* patients;
char * fileName;
int patientCapacity;
char * hospitalName;
int totalPatients;
};
Hospital::Hospital(int size){
patients = new Patient[size]; // allocating dynamic memory
// some initialization and processing here
}
Hospital::~Hospital(){
delete[] patients; //freeing up memory
}
I am having trouble with a programming assignment for my c++ class and I am not sure how I should be doing this to not get an error. I am pretty new to programming, so this will probably be really easy.
In my instructions, we have to create a class to work with other code that is given to us with some guidelines. I have three files: program.h, program.cpp, and main.cpp.
program.h
//program.h
#include <iostream>
#include <stdint.h>\\This program uses type uint32_t so had to include this
#include <cstdlib>
class Program
{
public:
Program(); //was told to create a default constructor to initiate values if none are given
Program(char *, uint32_t, float); //was told to create an overloaded default constructor to change variables in program
void SetName ( const char* ); //given by the professor
//other function prototypes are here but they are working fine.
private:
char * name_; //given by professor
uint32_t code_;//given by professor
float cost_;//given by professor
};
program.cpp
//program.cpp
//other functions from class are in this file, just not giving any issues
Program::Program(char * name,uint32_t code, float cost) : name_(name), code_(code), cost_(cost)
{
}
Program::Program() : name_(NULL), code_(0x00000000), cost_(0.0)
{
}
void Program::SetName(const char* name)
{
name_= name; //where the issue appears to occur since name is a const char *
}
currently trying to compile program.o using makefile and program.h program.cpp so the main.cpp does not matter. When i try to compile, i receive the following error:
clang++ -oprogram.h program.cpp
program.cpp:17:9: error: assigning to 'char *' from incompatible type 'const char *'
name_ = name;
Since the function was void SetName (const char*); was given by the professor and has to be used. I am not sure how to fix this error since the variable char * name_; was also given to us by the professor. Pointers still confuse me some, but any help would be greatly appreciated. I always thought that constant data can be passed to nonconstant data but not vise versa.
Important point just to get this out of the way:
char * name_;
Defines a pointer to a character. This just makes a pointer. It does not make a character. You will need to provide the character that is pointed at later. This pointer can be used to change the memory at which it points.
const char* name
Defines a pointer to a character that cannot be changed.
A value that cannot be changed is fundamentally different from a value that can be changed. You can copy the unchangeable value into the changable, but you cannot do the reverse because that would require changing the unchangeable value.
A pointer that can be used to change a value cannot be pointed at an unchangeable value to prevent the obvious problem of using the pointer to attempt to change the value.
What you need to do is copy.
But first, you need to allocate storage to hold the copy. This should be covered by your text, leaving one problem: How much storage is needed?
First, you have to know what a string is and how they are represented in C. Not C++, but C. C++ does it a little bit differently and your professor will get to that eventually. I hope. God, I really hope. In the meantime, the professor has you working with C-style strings.
strlen solves the how much storage problem, mostly. strlen will tell you the length of a properly formatted string of characters. What it doesn't tell you is implied by the definition of a character string. Hope you read the link.
Now that you know how much storage you need, you allocate the storage with new.
Now that you have a name_ pointing to enough storage, you can copy from the constant memory at name into it. strcpy should be helpful here.
This is wonderful, but leave you with a small problem: what if there already was storage at _name? Shucks. We just overwrote the pointer to it. This is called a memory leak and is no small part of why C++ does strings differently.
OK, so before allocating storage for name_and copying the storage at name into it, first you need to test to make sure name_ is empty. Couple of ways to do this:
Set a canary value. A canary is an impossible value; something that you will never see. Typically for pointers we use NULL, a glorified 0. There is nothing at address zero by convention, so if you see a pointer pointing to zero something is up. If in the constructor you make sure that name_ is NULL, you will have an easy way to know if name_ isn't pointing at data yet.
Keep a length value and set it to zero in the constructor. If the length is zero, there's nothing there. As an added bonus since this allow you to know the length of your storage, you can compare it to the amount of storage needed by the new string. If the new string is the same size or smaller, you can write over the old string.
If you need to replace name_'s storage, delete[] the old storage before allocating new storage.
Putting it all together, and using option 2 because it's better, you get:
int len = strlen(name)
if len > length_
delete name_
name_ = new storage
strcpy(name_, name)
Note there are a few pieces missing you'll have to fill out.
And just to be an ass, this is what all that would look like with C++ strings:
name_ = name;
Look familiar? Aren't you glad your professor decided to teach you to program in C++ the worst, hardest way first?
There may be some typos. You have space in
#include < iostream >
Remove the space
#include <iostream>
Change char to
const char * name_;
Add semicolon after the last } in the Program class definition.
Example on the code:
main.cpp
#include <iostream>
#include "program.h"
using namespace std;
int main(int argc, char const *argv[]) {
cout << "Hello, World!" << endl;
char const * name = "Claus";
uint32_t code = 1967;
float cost (3.14f);
Program p (name, code, cost);
cout << "getName(): " << p.getName() << endl;
return 0;
}
program.cpp
#include "program.h"
Program::Program() {};
Program::~Program() {};
Program::Program(char const * name,uint32_t code, float cost) : name_(name), code_(code), cost_(cost) {}
void Program::SetName(const char* name) {
name_= name; //where the issue appears to occur since name is a const char *
}
char const* Program::getName() {
return name_;
}
program.h
#ifndef PROGRAM_H
#define PROGRAM_H
#include <stdint.h>
class Program {
public:
Program(); //was told to create a default constructor to initiate values if none are given
~Program();
Program(const char * , uint32_t, float); //was told to create an overloaded default constructor to change variables in program
void SetName (const char* );
const char* getName();
private:
const char * name_;
unsigned int code_;
float cost_;
};
#endif // PROGRAM_H
On my mac I compile it with
clang++ -std=c++11 -Wall -o main main.cpp program.cpp
I get warning about unused variables but that's OK.
I was inspired by user4581301's response to learn a bit C. C++ does alleviate it alot.
In program.cpp
Program::Program(char * name, uint32_t code, float cost) {
unsigned int len = strlen(name);
name_ = new char[len];
strcpy(name_, name);
code_ = code;
cost_ = cost;
}
void Program::SetName(const char* name) {
unsigned int len = strlen(name);
delete name_;
name_ = new char[len];
strcpy(name_, name);
}
This link helped me as well: how to initialize a char pointer in a class?
regards
Claus
When we are using a "double" pointer to class, what are we writing in the constructor with arguments? Are we using one pointer for the allocated memory ?
Here is the code. It doesn't compile and I don't understand why. Thanks for the help.
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
class Article{
private:
char title[100];
char author[50];
char *content;
bool publish;
public:
Article(char *title="", char *author="", char *content="", bool publish=0){
strcpy(this->title, title);
strcpy(this->author, author);
this->content=new char[strlen(content)+1];
strcpy(this->content, content);
this->publish=publish;
}
void show(){
cout<<title<<endl;
cout<<author<<endl;
cout<<content<endl;
}
~Article(){
delete [] content;
}
};
class Newspaper{
private:
char name[100];
Article **p;
int articles;
Article first;
public:
Newspaper(char *name="", Article **p=Article(), int articles=0, Article first=Article()){
strcpy(this->name, name);
}
};
int main() {
char title[100], author[50], content[100];
int n;
cin >> n;
char name[100];
cin.getline(name, 100);
cin.getline(name, 100);
Article first("VAZNO","OOP","Vezba:OOP",true);
Newspaper v(name,first);
Article **s = new Article*[n];
for(int i = 0; i < n; ++i) {
cin.getline(title, 100);
cin.getline(author, 50);
cin.getline(content, 100);
v.addArticle(Article(title, author, content, true)); //se koristi copy konstruktor
}
v.showFirst();
v.showLongest();
cout << v.totalofauthor(author) << endl;
for(int i = 0; i < n; ++i) {
delete s[i];
}
delete [] s;
return 0;
}
Solution to your question:
From your code it seems that a Newspaper uses a pointer to a pointer (what you call a double pointer) for keeping track of the Articles:
Newspaper(char *name, Article **p , // This would be ok
int articles = 0, Article first = Article())
but that you've trouble to define a default argument for it:
Newspaper(char *name="", Article **p=Article(), // oops doesn't compile
int articles = 0, Article first = Article())
The reason is that a "double" pointer is not the same as the object itself. If you want a default argument here, you must provide a double pointer as well.
This code does exactly this:
Newspaper(char *name = "", Article **p = new Article*, // this is ok !
int articles = 0, Article first = Article()){
So this is the solution to your question.
But what's your problem ?
But what's the purpose or providing a dummy pointer, pointing to nowhere as default argument ?
Later you try to create a Newspaper based on an article again:
Newspaper v(name, first); // won't work, because first is not a pointer either
So the problem is not the constructor, but the whole principle. It seems that you really want to create a Newspaper based on an Article, and that you use defaults to cover the case where someone wants to create a Newspaper without Article.
Apparently your design also foresees that Articles may be added dynamically:
v.addArticle(Article(title, author, content, true));
Finally it seems that you really have a problem with pointers: when in the constructor you write, you didn't initialise the poitner to a memory region large enough to hold the name:
Newspaper(char *name = "", ...) {
strcpy(this->name, name); // Ouch !! pointer name is not initalized !
}
So once you'll get your code compiled, your programme won't work ! As this->name is a pointner that is never initialized, your strcpy() will cause memory corruption and undefined behaviour (crash!?).
Recommendations
First, get a book or a tutorial to understand and master pointers. If you do'nt you'll quickly be completely lost in your C++ class.
In the meantime, get rid of your char* and strcpy() and alike, and use std::string instead.
Last, consider the use of std::vector to manage the dynamic Article container. A dynamic array of poitners implemented with Article** would need extra logic, such as maintaining the size, reallocation of memory once the number of article grows, not speaking of the ownership (allocation/deallocation) of the Articles you put in the array.
Based on these recommendations, your Newspaper would look like this:
class Newspaper{
private:
string name;
vector<Article> p; // p.size() will provide the number of articles
public:
Newspaper(string name = "") : name(name) { } // empty newspaper
Newspaper(string name, Article& a) : Newspaper(name) { // combo
addArticle(a);
}
void addArticle(Article &a) {
p.push_back(a); // add and article to the vector
}
... // rest of the code, here
};
And here a little more
The issue that I am having is that I am trying to build a DLL. And I am using char instead of strings to store information.
I have defined the following in the header file:
class Test{
public:
int qLenght;
char firstName[];
char surName[];
};
I am having problems inputting codes from the main program using the following:
int main()
{
Test theTest;
theTest.firstName[0] = {"Mike Smith","Jonny Vegas","Jimmy Woo"};
}
I have included the header code at the top of my main project.
It won't let me add to the char array. This may seem like a stupid question but I am struggling and hopefully someone can shed some light as to where I am going wrong. Am I missing a parameter?
Your class needs to know how much memory to allocate when you instantiate the class (which is not the same time as you assign the values).
class Test
{
public:
char firstName[2][100];
};
int main()
{
Test theTest;
strcpy(theTest.firstName[0], "Mike Smith");
strcpy(theTest.firstName[1], "Jonny Vegas");
return 0;
}
Alternatively, you can allocate memory for the strings dynamically at the time of assignment, but then you need to remember to free it again:
class Test{
public:
char *firstName[2];
};
int main()
{
Test theTest;
theTest.firstName[0] = strdup("Mike Smith");
theTest.firstName[1] = strdup("Jonny Vegas");
// do stuff
free(theTest.firstName[0]);
free(theTest.firstName[1]);
return 0;
}