Thread: Dynamic Array Memory Issue

  1. #1
    Registered User
    Join Date
    Jun 2019
    Posts
    5

    Dynamic Array Memory Issue

    Hello,


    I'm new to dynamic memory in C++ and am working on a terminal program that's meant to act as a grade calculator. A user can add grades and the program will calculate their average GPA as well as display all the grades they entered.


    To add the grades I'm using parallel dynamic arrays (one for the number score and one for the corresponding letter grade) that should technically grow infinitely. The code I have works, but after adding 8 elements in the array i get the following error:


    main: malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) &7 ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
    Aborted (core dumped)
    This is what it looks like when running my program as is, as you can see it displays the first 7 elements of my array:

    Main Menu:
    1. Add Grade
    2. Display All Grades
    3. Process All Grades
    4. Quit Program


    1


    Add a grade: 42


    You added 42.


    Main Menu:
    1. Add Grade
    2. Display All Grades
    3. Process All Grades
    4. Quit Program


    2


    # Score Grade
    0 84 B
    1 95 A
    2 82 B
    3 75 C
    4 96 A
    5 95 A
    6 42 F


    Main Menu:
    1. Add Grade
    2. Display All Grades
    3. Process All Grades
    4. Quit Program


    1
    Carroll: malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
    Aborted (core dumped)



    Here's my function code:


    Code:
     int* addGrade (int* array, int size)
    {
    
    
      int* pTemp = nullptr;
      int temp; //temp array for conditional
      pTemp = new int[size];//create new array that will have size of size
         
      //loop to copy over array
      for (int i=0; i < size; i++)
      {
         pTemp[i]=array[i];
      }
        
      cout << endl << "Add a grade: ";
      cin >> temp;
         
      //if score isn't between 0-100, have them re-enter
      while ( temp > 100 || temp < 0 )
      {
         cout << endl << "That's an invalid input, please make sure your score is between 0-100."
              << endl << "Add a grade: ";
         cin >> temp;
      }
         
      pTemp[size] = temp; //assign score to new array element
      delete[] array;
    
    
      array = pTemp; //grade array now pointing at temp
      pTemp = nullptr;
         
      delete[] pTemp;
      cout << endl << "You added " << array[size] << "." << endl;
        
      return(array);//return new address of array
    }
    And here's how I'm calling the function in main:


    Code:
     //Add a grade 
         if (retval == 1)
         {
    
    
            pGrade = addGrade(pGrade, size); //assign new ptr address to pGrade on return
            pLetterGrade = addLetterGrade(pLetterGrade, pGrade, size);
            size++; //increase size of arrays
            retval=Menu(); //display menu again
    
    
         }
    I have tried using valgrind but I don't quite understand what it means, if anyone does this is what it outputs after the 1st addition to the grade array:


    Main Menu:
    1. Add Grade
    2. Display All Grades
    3. Process All Grades
    4. Quit Program


    1


    Add a grade: 54
    ==12110== Invalid write of size 4
    ==12110== at 0x10999C: addGrade(int*, int) (Carroll.cpp:226)
    ==12110== by 0x1092FD: main (Carroll.cpp:100)
    ==12110== Address 0x5b7e580 is 0 bytes after a block of size 0 alloc'd
    ==12110== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==12110== by 0x109895: addGrade(int*, int) (Carroll.cpp:207)
    ==12110== by 0x1092FD: main (Carroll.cpp:100)
    ==12110==


    ==12110== Invalid read of size 4
    ==12110== at 0x109A0F: addGrade(int*, int) (Carroll.cpp:233)
    ==12110== by 0x1092FD: main (Carroll.cpp:100)
    ==12110== Address 0x5b7e580 is 0 bytes after a block of size 0 alloc'd
    ==12110== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==12110== by 0x109895: addGrade(int*, int) (Carroll.cpp:207)
    ==12110== by 0x1092FD: main (Carroll.cpp:100)
    ==12110==
    You added 54.
    ==12110== Invalid read of size 4
    ==12110== at 0x109B30: addLetterGrade(char*, int*, int) (Carroll.cpp:288)
    ==12110== by 0x109317: main (Carroll.cpp:101)
    ==12110== Address 0x5b7e580 is 0 bytes after a block of size 0 alloc'd
    ==12110== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==12110== by 0x109895: addGrade(int*, int) (Carroll.cpp:207)
    ==12110== by 0x1092FD: main (Carroll.cpp:100)
    ==12110==
    ==12110== Invalid write of size 1
    ==12110== at 0x109B47: addLetterGrade(char*, int*, int) (Carroll.cpp:288)
    ==12110== by 0x109317: main (Carroll.cpp:101)
    ==12110== Address 0x5b7e5c0 is 0 bytes after a block of size 0 alloc'd
    ==12110== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==12110== by 0x109AE4: addLetterGrade(char*, int*, int) (Carroll.cpp:279)
    ==12110== by 0x109317: main (Carroll.cpp:101)
    ==12110==

    Any assistance is appreciated.
    Thank you!

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    This line is likely wrong.

    pTemp = new int[size];//create new array that will have size of size

    You either need to use size+1 or pass in size+1

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Your idea of creating a new dynamic array and copying over the old one to it each time you add a grade is rather expensive: instead of taking amortised constant time, addGrade will take linear time, which means adding N grades will take quadratic time in N rather than amortised linear time.

    A more efficient approach is to track both size (number of elements in use) and capacity (number of elements allocated) of the dynamic array, increasing the capacity by a multiple each time you need to expand the dynamic array.

    Instead of doing this yourself, you should use a std::vector<int> to store the grades. This way, addGrade could become:
    Code:
    void addGrade(std::vector<int>& grades)
    Notice that I use a reference parameter so that grades in the caller will be modified. Because you didn't pass the pointer by reference, this line doesn't do what the comment says it does:
    Code:
    array = pTemp; //grade array now pointing at temp
    Or perhaps you can say that the comment is correct, but it has no effect on the actual grade array from the caller, i.e., you're relying on assignment back to the pointer in the caller instead.
    Last edited by laserlight; 02-14-2020 at 08:02 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Quote Originally Posted by stahta01 View Post
    This line is likely wrong.

    pTemp = new int[size];//create new array that will have size of size

    You either need to use size+1 or pass in size+1

    Tim S.
    Because the line below is undefined and will likely cause program to crash if size is the dimension of the array pTemp.

    Code:
    pTemp[size] = temp; //assign score to new array element
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  5. #5
    Registered User
    Join Date
    Jun 2019
    Posts
    5
    Quote Originally Posted by stahta01 View Post
    Because the line below is undefined and will likely cause program to crash if size is the dimension of the array pTemp.

    Code:
    pTemp[size] = temp; //assign score to new array element
    Thank you so much! Replacing that line with
    Code:
    pTemp = new int[size +1];
    fixed the issue; it's functioning as expected now. I'm just curious, how was the code able to work (up to the 8th element) before with that line just holding the value of size?

    Thanks for your help.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by olympus017 View Post
    I'm just curious, how was the code able to work (up to the 8th element) before with that line just holding the value of size?
    The simple answer is that you're looking at the effects of undefined behaviour because accessing an array out of bounds is undefined behaviour. Going deeper, it could be that you were modifying other memory that you could modify but didn't notice it until you started modifying memory that you could not modify, or perhaps the allocator allocated a little more memory than explicity requested
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic Memory Array
    By darren78 in forum C++ Programming
    Replies: 8
    Last Post: 07-28-2010, 07:37 AM
  2. dynamic memory allocation char array
    By waxydock in forum C Programming
    Replies: 2
    Last Post: 05-12-2007, 07:05 AM
  3. Dynamic memory alloction for my array of struct
    By pears0 in forum C Programming
    Replies: 13
    Last Post: 03-11-2005, 11:53 AM
  4. dynamic memory alloc. for array elements
    By Unregistered in forum C++ Programming
    Replies: 9
    Last Post: 06-04-2002, 05:14 PM

Tags for this Thread