3

I made an Array of Class st[5]. And tried to display st[5]'s data by using a function. But it doesn't work.

Only the 1st class (st[0]) is displayed, and the 'debug error Message'. I don't know what the problem is.

A main function is at the bottom.

#include <iostream>
using namespace std;

#define MAX 5       //size of array

//Class 'Student' 
class Student
{
public:
    int num;
    char name[10];
};

//Class 'Lscore' extends Student (virtual)
class Lscore : virtual public Student   
{
public: 
    int eng;    
};

//Class 'Nscore' extends Student (virtual)
class Nscore : virtual public Student
{
public:
    int math;   
};

//Class 'Totscore' extends Lscore, Nscore
class Totscore : public Lscore, public Nscore
{
public:
    Totscore();     //Constructor1
    Totscore(char name[], int num, int eng, int math); //Constructor2
    void Display();     //Print Myself
};

//Constructor1
Totscore::Totscore( )
{
}

//Constructor2
Totscore::Totscore(char name[10], int num, int eng, int math)
{       
    strcpy_s(this->name, 10, name);
    this->num = num;    
    this->eng = eng;
    this->math = math;  
}


//Print Myself
void Totscore::Display(){
    cout<<this->num<<"  "<<this->name<<"  ";
    cout<<this->eng<<"  "<<this->math<<"  "<<endl;
}


//Print Array (--- Problem Part !! ---)
void PrintArray(Totscore *stu){ 
    for(int i=0; i< MAX; i++){
        stu[i].Display();       
    }

}

//Main Function
int main(){
    Totscore *st[MAX];      //Class Array 'st'

    st[0] = new Totscore("A",101,85,77);
    st[1] = new Totscore("B",102,90,89);
    st[2] = new Totscore("C",103,80,55);
    st[3] = new Totscore("D",104,75,85);
    st[4] = new Totscore("E",105,85,85);

    PrintArray(*st);
}

And run screen is following. (I can't upload an image because my reputation is low.)

101  A  85  77

And 'Debug error message' displayed...

3
  • Quite amazingly, your code works with a very minor modification when compiled with g++ under MacOS X. I switched to using strncpy(this->name, name, 10);, and the code printed five lines quite nicely. Commented Dec 10, 2011 at 14:22
  • While I was answering your question you REMOVED it. So I couldn't post the answer, so I discarded it permanently. Now, that the question reappeared again I would have to type everything again. That would be double work for a simple question (so I didn't, especially since there is a correct answer anyway). Please don't do that in the future! Commented Dec 10, 2011 at 16:10
  • @ CygnusX1 . Ok, I see. Sorry for that. I'm first time in 'StackOverflow', so I didn't know How to use correctly. I'm Sorry. Commented Dec 10, 2011 at 19:11

5 Answers 5

4

You're creating an array of pointers here:

Totscore *st[MAX];

But you're passing the first element:

PrintArray(*st);

Changing your function to take a pointer to the entire array should work:

void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; i++){
        stu[i]->Display();       
    }
}

PrintArray(st);
Sign up to request clarification or add additional context in comments.

2 Comments

OMG. Thank you very much!!!!!!!! The problem solved. Thank you so much!!!!! Sorry for my low reputation, I can't vote.
@NatuerConservation You can't vote but you can accept this as an answer. Just click the tickmark on the left.
1

Few major problems leading to undefined behavior:

  1. Default constructor of Student does not initialize its char array.
  2. Arrays passed by value into constructors.
  3. Incorrect iteration trough array. Memory layout of array of objects is different from array of pointers to objects.

Well, there is also a memory leak, many unnecessary operations just to initialize data. You should use constructor initialization lists instead. There is no strcpy_s function in C/C++, it is a terrible Microsoft invention. Why not to use portable strncpy instead?

Here is a bit improved code:

#include <cstring>
#include <iostream>

using namespace std;

#define MAX 5       //size of array

//Class 'Student' 
class Student
{
public:
    Student (int num = 0) : num (num)
    {
        name[0] = '\0';
    }

    Student (const char *name, int num = 0) : num (num)
    {
        strncpy (this->name, name, sizeof (this->name));
    }

    int num;
    char name[10];
};

//Class 'Lscore' extends Student (virtual)
class Lscore : virtual public Student   
{
public: 
    Lscore (int eng = 0) : eng (eng) {}
    int eng;    
};

//Class 'Nscore' extends Student (virtual)
class Nscore : virtual public Student
{
public:
    Nscore (int math = 0) : math (math) {}
    int math;   
};

//Class 'Totscore' extends Lscore, Nscore
class Totscore : public Lscore, public Nscore
{
public:
    Totscore() {}     //Constructor1
    Totscore(const char *name, int num, int eng, int math); //Constructor2
    void Display();     //Print Myself
};

//Constructor2
Totscore::Totscore(const char *name, int num, int eng, int math)
        : Student (name, num), Lscore (eng), Nscore (math)
{       
}


//Print Myself
void Totscore::Display(){
    cout<<this->num<<"  "<<this->name<<"  "
        <<this->eng<<"  "<<this->math<<"  \n";
}


//Print Array (--- Problem Part !! ---)
void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; ++i){
        stu[i]->Display();       
    }

}

void DeleteArray(Totscore **stu){ 
    for(int i=0; i< MAX; ++i){
        delete stu[i];
    }
}

//Main Function
int main(){
    Totscore *st[MAX];      //Class Array 'st'

    st[0] = new Totscore("A",101,85,77);
    st[1] = new Totscore("B",102,90,89);
    st[2] = new Totscore("C",103,80,55);
    st[3] = new Totscore("D",104,75,85);
    st[4] = new Totscore("E",105,85,85);

    PrintArray(st);
    DeleteArray (st);
}

2 Comments

I don't think passing arrays by value is possible. char name[10] is the same as char* name
Thank you very much for your detailed explain. And sorry for my low reputation, I can't vote. Thank you so much for very helpful explain!!
1

This code is painful to look at. A couple of tips that you can use to quickly and easily improve your code in general:

In C++, favor const over #define for constants.

#define MAX 5  // Instead of this...
const int MAX = 5;  // ...do this.

Likewise, user std::string name over char *name or char name[10]. Otherwise, you're just writting C with classes, and there's enough of that out there already, unfortunately. Don't add to the pain. :)

Learn to use the standard containers types (vector, list, set and friends) instead of bare arrays. There's no reason not to and the built-in functionality they provide is amazing! There's a learning curve, of course. But you will come out much better in the end.

1 Comment

Thank you so much for your kind explain. I understand. I'll change.
1

If you want an array of objects you must declare the array as:

Totscore st[MAX];

And allocate Totscore objects on the stack (remove "new"). Finally, call the print function without dereferencing as:

PrintArray(st);

And your original code will work...

4 Comments

Oh, Thank you so much for your explain. This way is good, too. And if change to 'void PrintArray(Totscore stu[])', This work. Thank you!!!
@NatuerConservation "Totscore * a" is the same as "Totscore a[]" as arrays essentially decay into pointers to the first element...
@NatuerConservation Also read through the other post. There are a few good recommendations. Try to avoid preprocessor ("#define MAX 5"). Prefer allocation on the stack, if you don't need a heap object. Remember to deallocate heap memory when using heap objects. Consider using STL containers (vector) and algorithms.
@NatuerConservation I would recommend looking at pointers, references, values and difference between heap and stack objects in C++. Also find out more about STL and what it provides.
1

First, I will tell you what you need to do (without asking you to change the whole code) in order to make your code work, then explain why your code doesn't work:

Implement your printArray as:

void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; i++){
        stu[i]->Display();     
    }
}

then call it as:

PrintArray(st);

This should work.

Now why your original code doesn't work is because you're passing the first element of array, which cannot be used to traverse the array which is declared as array of pointers. Since st is declared as array of pointers, so you need to pass the address of first element of the array, rather than the element itself, so that you can traverse through the array of pointers. Note that the type of element of the array is Totscore*, so its address will be Totscore**.


Well that is very complicated for beginners, so I would suggest a better, robust and easy alternative. Use std::vector as:

std::vector<Totscore> st;

then call .push_back() to insert elements to it:

st.push_back(Totscore("A",101,85,77));
st.push_back(Totscore("B",102,90,89));
st.push_back(Totscore("C",103,80,55));
//etc

PrintArray(st);

then implement PrintArray as:

void PrintArray(const std::vector<Totscore> & stu)
{ 
    for(size_t i=0; i< stu.size(); i++){
        stu[i].Display();     
    }
}

Now there is one more very little change you need to make in your code. Make the Display() function a const member function.

void Display() const;
               ^^^^^ //this makes the  function const!
                     //in its definition too, write const!

Done!

5 Comments

why should the function declaration be void PrintArray(Totscore **stu); when passing PrintArray(st);
@Jagannath: Because st is declared as array of pointers, so you need to pass the address of the first element of array, rather than the element itself, so that you can traverse through the array of pointers. Also, see my answer, I updated it with more explanation.
Pass the name of the array variable itself is passing the address of the first element of the array.
@Jagannath: Yes. That is what I'm saying. Where do you disagree with me? Btw, if you write printArray(st), you've to write the function as void printArray(Totscore **stu), because the type of st is compatible with Totscore**, not with Totscore*.
Thank you very much for your kind explain. Sorry for my low reputation, I can't vote. But Thank you!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.