Results 1 to 17 of 17
  1. #1
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Thumbs up SOLVED: Array as class constructor will not copy elements, only reference

    I have been trying to figure this out for over a day now. I started trying to teach myself to program using Java a few weeks ago and I am working my way through a book. I am trying to create a program described in the book but in a different, more extensible, way. Since I am not doing it by the book, I can't look and find the answer there =) I hope someone can help.

    The program sets up a "student" class with a String field "name" and a int array field "grades".

    It sets up a "course" class consisting of an array of students, teacher name, subject, and number of exams. It also has some methods for taking in info about the course and its students and doing some minor math on the info (averages).

    The issue is that the "grades" array for each student object in the student array myStudents ends up being set to the data entered for the final-entered student.

    I have tried a lot of different array copying techniques in the constructor for Student but none of them work. Clearly, the issue is that I am passing and copying only a reference rather than actual substantive data for each array. The program keeps track of names on a per-Student basis just fine. String and array are both reference variables so I dont see why one works and the other is MISBEHAVING!

    I will go ahead and post all the code. Thanks for taking a look, let me know what you think could fix it.

    Student class

    Java Code:
    public class Student {
    
        int grades[];
        public String name;
    
    
        public Student (String n, int g[]){
    
            this.name = n;
            this.grades = new int[g.length];
            //java.lang.System.arraycopy(g, 0, grades, 0, g.length);
            //grades = g.clone();
            for (int loop=0;loop<g.length;loop++){
                this.grades[loop] = g[loop];
            }
            
        }
    
        double studentAverage (){
    
        int total = 0;
    
        for (int loop=0;loop<grades.length;loop++){
    
            total += grades[loop];
        }
    
        double avg = (double) total / grades.length;
        return avg;
        }
    }
    Course class

    Java Code:
    public class Course {
    
        int numStudents;
        int numExams;
        String instructor;
        String subject;
        Student myStudents[];
    
        public Course (int s, String i, String sub, int e) {
    
            numStudents = s;
            instructor = i;
            subject = sub;
            numExams = e;
            myStudents = new Student[s];
    
        }
    
        double classAverage () {
    
            double avg;
            int total = 0;
    
            for (int loop=0;loop<myStudents.length;loop++){
                total += myStudents[loop].studentAverage();
            }
    
            avg = (double) total / myStudents.length;
            return avg;
        }
    
        void collectInfo (){
    
            Scanner input = new Scanner(System.in);
    
            for (int loop=0;loop<myStudents.length;loop++){
    
                int grades[] = new int[numExams];
    
                System.out.printf("\nPlease enter the name of student#%d:\n", loop+1);
                String name = input.next();
    
                for (int loop2=0;loop2<grades.length;loop2++){
    
                System.out.printf("\nPlease enter %s's grade on exam #%d:\n", name, loop2+1);
                grades[loop2] = input.nextInt();
    
                }
                myStudents[loop] = new Student(name, grades);
    
            }
    
        }
    
        void displayInfo (){
    
            for (int loop=0;loop<myStudents.length;loop++){
    
                System.out.printf("\n%s received an average grade of %.2f.\n", myStudents[loop].name, myStudents[loop].studentAverage());
    
            }
    
            System.out.printf("The class average for the course %s tought by %s is:\n\t%.2f\n", subject, instructor, classAverage());
        }
    
    }
    And for completion, the application:

    Java Code:
    public class Application {
    
        public static void main (String args[]){
    
    
            //Receive initial parameters
            Scanner input = new Scanner(System.in);
            System.out.println("Hello, please enter your name:\n>");
            String name = input.next();
            System.out.println("Please enter the name of your course:\n>");
            String course = input.next();
            System.out.println("Please enter the number of students in your course:\n>");
            int students = input.nextInt();
            System.out.println("Please enter the number of exams each student takes:\n>");
            int numExams = input.nextInt();
    
            //Create new Course object based on parameters
            Course myCourse = new Course (students, name, course, numExams);
    
            //Collect student info
            myCourse.collectInfo();
    
            //Display results
            myCourse.displayInfo();
    
    
        }
    
    }
    Solved: IDE (Netbeans) malfunctioning. switched to Eclipse and same code works fine.
    Last edited by Lucificate; 07-08-2010 at 10:52 PM.

  2. #2
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    issue is that the "grades" array for each student object in the student array myStudents ends up being set to the data entered for the final-entered student.
    Try adding some debugging code using println()s to show when and where the values are being changed in the program. See Arrays.toString() for a way to print out contents of an array.

  3. #3
    m00nchile is offline Senior Member
    Join Date
    Feb 2010
    Location
    Ljubljana, Slovenia
    Posts
    470
    Rep Power
    5

    Default

    You already figured out the problem, every student gets the identical grade array, because they share the same reference. The answer is, of course, to dereference the array before using it again, eg:
    Java Code:
    int[] grades;
    for(bla;bla;bla) {
      grades = new int[someNumber];
      //rest of code
    }
    Ever seen a dog chase its tail? Now that's an infinite loop.

  4. #4
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    I just ran the code and it worked fine.

  5. #5
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    Thanks for the quick responses.

    Norm, I actually have already put debugging checks in to see what is happening with the data. What they show is that each time the outer for-loop in collectInfo() cycles, the values found in the grades array in each Student class are updated with the values from the latest iteration of the for-loop. Previously entered values are overwritten. If I check the values of each Student class in the array myStudents at the end of each for-loop cycle in collectInfo() they all have the latest entered data. This is what led me to conclude that I am just passing a reference rather than the actual data.

    This has me super confused. It seems that each time the for-loop in collectInfo() cycles, it reinitializes the array "grades" found in collectInfo(). It then populates that array based on user input. It then, at the conclusion of the for-loop, uses that collected info found in the array grades to instantiate another Student object within the Course array myStudents.

    The constructor in class Student first instantiates it own "grades" array and takes the input array passed from collectInfo() and parses through it copying the elements.

    It seems that even if array "grades" in collectInfo() continually points to the same memory location and each iteration of the for-loop overwrites the data there with new data, it shouldnt matter - the previous data should have already been passed to a new Student object and copied to the "grades" array in Student.

    It all seems to plain. Im starting to think my compiler is broke =)

    m00nchile,

    I'm not sure how to implement the fix you have posted. It seems to me that I do create a new "grades" array on each pass of the outer for-loop in collectInfo(). I also create a new "grades" array in the Student class constructor based on the size of the the grades array created in collectInfo() and then copy the contents into the array in Student.

    Doesn't the code already do what you are saying to do?

  6. #6
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    Norm,

    You ran the code as I have it posted and it worked fine? Did you use a couple students with a couple exams each?

  7. #7
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    Here is my output:

    Java Code:
    Hello, please enter your name:
    >
    tom
    Please enter the name of your course:
    >
    ai
    Please enter the number of students in your course:
    >
    2
    Please enter the number of exams each student takes:
    >
    2
    
    Please enter the name of student#1:
    wiz
    
    Please enter wiz's grade on exam #1:
    90
    
    Please enter wiz's grade on exam #2:
    100
    
    Please enter the name of student#2:
    dunce
    
    Please enter dunce's grade on exam #1:
    0
    
    Please enter dunce's grade on exam #2:
    10
    
    wiz received an average grade of 5.00.
    
    dunce received an average grade of 5.00.
    The class average for the course ai tought by tom is:
            5.00

  8. #8
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    For testing I don't like to use Scanner, so I commented it out.
    Here's my code:
    Java Code:
    import java.util.*;
    
    public class ProblemWithArray {
    
    class Student {
    
        int grades[];
        public String name;
    
    
        public Student (String n, int g[]){
    
            this.name = n;
            this.grades = new int[g.length];
            //java.lang.System.arraycopy(g, 0, grades, 0, g.length);
            //grades = g.clone();
            for (int loop=0;loop<g.length;loop++){
                this.grades[loop] = g[loop];
            }
            
        }
    
        double studentAverage (){
    
        int total = 0;
    
        for (int loop=0;loop<grades.length;loop++){
    
            total += grades[loop];
        }
    
        double avg = (double) total / grades.length;
        return avg;
        }
    }
      class Course {
    
        int numStudents;
        int numExams;
        String instructor;
        String subject;
        Student myStudents[];
    
        public Course (int s, String i, String sub, int e) {
    
            numStudents = s;
            instructor = i;
            subject = sub;
            numExams = e;
            myStudents = new Student[s];
    
        }
    
        double classAverage () {
    
            double avg;
            int total = 0;
    
            for (int loop=0;loop<myStudents.length;loop++){
                total += myStudents[loop].studentAverage();
            }
    
            avg = (double) total / myStudents.length;
            return avg;
        }
    
        void collectInfo (){
    
    //        Scanner input = new Scanner(System.in);
    
            for (int loop=0;loop<myStudents.length;loop++){
    
                int grades[] = new int[numExams];
    
                System.out.printf("\nPlease enter the name of student#%d:\n", loop+1);
                String name = "Name" + loop; //input.next();
    
                for (int loop2=0;loop2<grades.length;loop2++){
    
                   System.out.printf("\nPlease enter %s's grade on exam #%d:\n", name, loop2+1);
                   grades[loop2] = loop + loop2; //input.nextInt();
    
                }
                myStudents[loop] = new Student(name, grades);
    
            }
    
        }
    
        void displayInfo (){
    
            for (int loop=0;loop<myStudents.length;loop++){
    
                System.out.printf("\n%s received an average grade of %.2f.\n", 
                                   myStudents[loop].name, myStudents[loop].studentAverage());
                System.out.println("grades=" + Arrays.toString(myStudents[loop].grades));
    
            }
    
            System.out.printf("The class average for the course %s tought by %s is:\n\t%.2f\n", 
                              subject, instructor, classAverage());
        }
    
    }
    
        public static void main (String args[]){
          new ProblemWithArray();
        }
    
        public ProblemWithArray() {
            //Receive initial parameters
            Scanner input = new Scanner(System.in);
            System.out.println("Hello, please enter your name:\n>");
            String name = "My Name"; //input.next();
            System.out.println("Please enter the name of your course:\n>");
            String course = "My course"; //input.next();
            System.out.println("Please enter the number of students in your course:\n>");
            int students = 3; //input.nextInt();
            System.out.println("Please enter the number of exams each student takes:\n>");
            int numExams = 4; //input.nextInt();
    
            //Create new Course object based on parameters
            Course myCourse = new Course (students, name, course, numExams);
    
            //Collect student info
            myCourse.collectInfo();
    
            //Display results
            myCourse.displayInfo();
    
    
        }
    
    }
    Here's its output:
    Running: java.exe -classpath D:\JavaDevelopment;. -Xmx512M ProblemWithArray

    Hello, please enter your name:
    >
    Please enter the name of your course:
    >
    Please enter the number of students in your course:
    >
    Please enter the number of exams each student takes:
    >

    Please enter the name of student#1:
    Please enter Name0's grade on exam #1:
    Please enter Name0's grade on exam #2:
    Please enter Name0's grade on exam #3:
    Please enter Name0's grade on exam #4:
    Please enter the name of student#2:
    Please enter Name1's grade on exam #1:
    Please enter Name1's grade on exam #2:
    Please enter Name1's grade on exam #3:
    Please enter Name1's grade on exam #4:
    Please enter the name of student#3:
    Please enter Name2's grade on exam #1:
    Please enter Name2's grade on exam #2:
    Please enter Name2's grade on exam #3:
    Please enter Name2's grade on exam #4:
    Name0 received an average grade of 1.50.
    grades=[0, 1, 2, 3]

    Name1 received an average grade of 2.50.
    grades=[1, 2, 3, 4]

    Name2 received an average grade of 3.50.
    grades=[2, 3, 4, 5]
    The class average for the course My course tought by My Name is:
    2.00

    0 error(s)

  9. #9
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    well this is baffling. just doesnt work on mine. does this happen from time to time? good code just wont work on a per-machine/compiler basis?

  10. #10
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    Possible, but not frequent.
    Can you add some debug code to your version to show the contents of the grades[] array as it is created. See my code for the Arrays.toString() method.
    Add special code to show it for all students to see where it is being changed.

  11. #11
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    God, things are a mess. I dont get it. If i add a couple debug lines to collectInfo():

    Java Code:
    void collectInfo (){
    
            Scanner input = new Scanner(System.in);
    
            for (int loop=0;loop<myStudents.length;loop++){
    
                int grades[] = new int[numExams];
    
                System.out.printf("\nPlease enter the name of student#%d:\n", loop+1);
                String name = input.next();
    
                for (int loop2=0;loop2<grades.length;loop2++){
    
                System.out.println("grades=" + Arrays.toString(grades));
    
                System.out.printf("\nPlease enter %s's grade on exam #%d:\n", name, loop2+1);
                grades[loop2] = input.nextInt();
    
                }
                myStudents[loop] = new Student(name, grades);
                System.out.println("grades=" + Arrays.toString(myStudents[loop].grades));
    
            }
    
        }
    The debug lines dont print at all. I think something weird is happening with my compiler. Like it is using old code when compiling for some reason.

    Java/compiler info:

    Product Version: NetBeans IDE 6.9 (Build 201006101454)
    Java: 1.6.0_20; Java HotSpot(TM) Client VM 16.3-b01
    System: Windows Vista version 6.0 running on x86; Cp1252; en_US (nb)
    Last edited by Lucificate; 07-08-2010 at 08:11 PM. Reason: Added java/compiler info.

  12. #12
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    I'd bet it was the IDE before I'd suspect the javac command.

  13. #13
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    Ya the IDE, not the compiler. Still wrapping my head around this stuff =) Was just using "compiler" to refer to the whole setup.

    Welp, time to try a different one!

  14. #14
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    Welp, just installed eclipse, made no changes to source and it runs beautifully.

    Unbelievable. Probably worked on that for 7-8 hours yesterday and today.

    Not sure what to do to avoid wasting all that time. Tough for a newbie like me to come to the conclusion that its not me screwing up, rather its the damn IDE.

  15. #15
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

    Default

    When debugging, the more extraneous stuff you can remove from a test, the better.
    Isolate, isolate, isolate.

  16. #16
    Lucificate is offline Member
    Join Date
    Jul 2010
    Posts
    9
    Rep Power
    0

    Default

    I guess using notepad and command lineing javac is the most bareboned way I can do it?

    Man, you have been a huge help. Thanks a lot for putting some effort into this today. I have been really enjoying learning to code a bit and was really struggling trying to make sense of why things were going so poorly - I didn't wanna move onto something new until figuring it out =)

  17. #17
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,274
    Rep Power
    25

Similar Threads

  1. reference issue
    By Stephen Douglas in forum New To Java
    Replies: 29
    Last Post: 07-04-2010, 05:12 PM
  2. copy constructor
    By shadow7 in forum New To Java
    Replies: 6
    Last Post: 12-29-2009, 06:56 PM
  3. reference to elements in array
    By Igor in forum New To Java
    Replies: 1
    Last Post: 12-14-2007, 11:56 AM
  4. Replies: 1
    Last Post: 12-14-2007, 07:25 AM
  5. how to issue the command of Ctrl-C (copy) in Java
    By bilal_ali_java in forum Advanced Java
    Replies: 0
    Last Post: 07-18-2007, 03:14 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •