I am writing an application that reads from data files of a given format. In the file, I've dynamically created a 2D array of pointers to vector objects. Basically, it reads through the file, and when it finds a given string pattern, it stops and reads
while(getline(inputFile,tempTestString)){
// first for ACCEL
if(string::npos != tempTestString.find(ACCEL)){
sstream.str(tempTestString);
sstream >> pushBack;
cout << "position 1" << endl;
array[tempDim1][tempDim2].vectorName->push_back(pushBack);
cout << "position 2" << endl;
break;
}
}
now, pushBack is a large number, could be up to 20000, but it varies between files.
The problem with this code is that I'm not getting any run-time errors, or even any exceptions thrown, I tried catching them. The program simply finishes! To be sure, I added the cout << "position1" << endl; and cout << "position2" << endl; lines and the latter prints.
In case you haven't guessed:
tempTestString and ACCEL - string objects
sstream - stringstream object
array - 2D struct array in dynamic memory
vectorName - pointer to vector object, member of struct pointed to by array
ADDENDUM:
So, in response to some comments, here is the other portion of the code, where all the variables were created:
array
array = new structName* [tempDim1];
for(int i = 0; i < tempDim2; i++){
array[i] = new structName [tempDim2];
}
structName
struct structName{
vector<double>* vectorName;
vector<double>* vectorName1;
vector<double>* vectorName2;
};
tempDim1 and tempDim2 are both const ints, of values 2 and 3, respectively. pushBack can have a value of up to 20000
Try to correct this:
array = new structName* [tempDim1];
for(int i = 0; i < tempDim2; i++){
array[i] = new structName [tempDim2];
}
=>
array = new structName* [tempDim1];
for(int i = 0; i < tempDim1; i++){
array[i] = new structName [tempDim2];
}
You're using the wrong number of elements in your initialization.
array = new structName* [tempDim1];
for(int i = 0; i < tempDim2; i++){
array[i] = new structName [tempDim2];
}
i < tempDim2 is wrong; the array has tempDim1 elements.
I don't know if this is the problem, but it is a problem. If tempDim1 > tempDim2 then some elements of array[] are going to be uninitialized. (And if it's the other way around, you're corrupting memory.) The only way this would work is if tempDim1 and tempDim2 are the same by coincidence.
Related
I'm trying to create a 2D array of c-strings (for a specific school exercise; I'm forced to use c-strings for practice) using dynamic memory allocation. However, it seems that when accessing and writing to the second index of the array (second sub-array), the actual memory location that's used is the same of the first index.
The code:
#include <iostream>
#include <string>
int main()
{
int n_names; std::string current; const int SPACE_FOR_EACH_NAME = 100;
std::cout << "How many names to input? "; std::cin >> n_names; std::cin.ignore();
//dynamically allocate a multi-dimensional array
char** names;
names = new char* [n_names];
for (int i = 0; i < n_names; i++)
names[i] = new char[SPACE_FOR_EACH_NAME];
int count = 0;
while (count < n_names) {
std::cout << "Name " << ++count << ": ";
std::getline(std::cin, current);
names[count-1] = (char*) current.c_str(); //THE TROUBLE SEEMS TO BE HERE
}
for (int i = 0; i < n_names; ++i) {
for (int j = 0; j < SPACE_FOR_EACH_NAME; ++j) {
if (names[i][j] == '\0') break; //termination of the current name
std::cout << names[i][j];
}
std::cout << "\n";
}
//free allocated memory
for (int i = 0; i < n_names; ++i)
delete[] names[i];
delete[] names;
}
What the debugger shows when modifying the 'names' array (consider user inputs 2 names):
+ names[count-1] 0x00affbe8 "dude" char * //here count is 1
+ names[count-1] 0x00affbe8 "noice" char * //here count is 2
And the console just prints "noice" twice.
What's wrong?
The result of current.c_str() should never be stored for any length of time. Doing so is undefined behaviour, but it is likely, as here that that memory pointed to will be reused.
You put the char* from current.c_str() into names[0], then you put a new value into current and put current.c_str() into names[1]. But because you have changed current you also change names[0].
Also, in both cases, you are discarding the pointer you already created with names[i] = new char[SPACE_FOR_EACH_NAME];
This allocates a block of memory and puts it's address into names[0] (0 as a specific example). The next thing that happens with names[0] is names[0] = (char*) current.c_str(); which puts a different address into the variable. The address returned from the new is lost completely, causing a memory leak.
Instead of
names[count-1] = (char*) current.c_str();
try
std::strcpy(names[count-1],current.c_str())
So I am making a merge sort program in c++ that is supposed to take 5 arrays of size 10, 100, 1000, 10000, and 100000, and tell how many comparisons are made for each array. I was able to sort all arrays fine, but I ran into a stack overflow when trying to make a third object of my merge sort class. I made the first two objects of my merge sort class without any problems, but when I make a third object of my merge sort class, I get an error that there is a stack overflow. When I debug the program it points me to the .asm file, and since I don't know assembly I'm not sure what to think of this. I've run into this problem in the past, and it's because I forgot to dynamically allocate memory to array's. I looked back and all my array's have been dynamically allocated, so I'm not sure why I am getting this error. Here is my main, I marked what is giving me errors with asterisks. Any help is appreciated, this is my second question on here so don't destroy me please :)
//main.cpp
int main(){
int* tenArray;
int* hundArray;
int* thouArray;
int* tenThouArray;
int*oneHundThouArray;
tenArray = new int[9];
hundArray = new int[99];
thouArray = new int[999];
tenThouArray = new int[9999];
oneHundThouArray = new int[99999];
srand((unsigned int)time(NULL));
//Create arrays filled with random numbers
for (int i = 0; i < ARRAY_TEN; i++) {
tenArray[i] = rand();
}
for (int i = 0; i < ARRAY_HUND; i++) {
hundArray[i] = rand();
}
for (int i = 0; i < ARRAY_THOU; i++) {
thouArray[i] = rand();
}
for (int i = 0; i < ARRAY_TEN_THOU; i++) {
tenThouArray[i] = rand();
}
for (int i = 0; i < ARRAY_ONE_HUND_THOU; i++) {
oneHundThouArray[i] = rand();
}
MergeSort tenSort;
MergeSort hundSort;
//******************************************************************
MergeSort thouSort;//When typed the program will give an error
//******************************************************************
//Here I am just calling my sort function from implementation file:
//sorting 10 array
tenSort.sort(tenArray, 0, ARRAY_TEN - 1);
cout << endl << "Comparisons = " << tenSort.getCount() << endl;
//sorting 100 array
hundSort.sort(hundArray, 0, ARRAY_HUND - 1);
cout << endl << "Comparisons = " << hundSort.getCount() << endl;
//****************************************************************
//sorting thousand array
thouSort.sort(thouArray, 0, ARRAY_THOU - 1);
cout << "comparison = " << thouSort.getCount() << endl;
//****************************************************************
}
getCount just looks like this:
//in implementation
int MergeSort::getCount() {
return count;
}
If it helps the line in the asm file causing the error says:
test dword ptr[eax],eax ;probe page
Do the MergeSort constructors allocate any additional memory? It's possible you're actually running out of memory on the stack. The stack can only contain so much data, and declaring over a hundred-thousand integers multiple times could add up to quite a lot.
I created this function to change the size of the dynamic array
size = 4; //this is what size is in my code
int *list = new int[size] // this is what list
void dynArray::doubleSize( )
{
int *temparray;
int currentsize = size;
int newsize = currentsize * 2;
temparray = new int[newsize];
for (int i = 0 ; i < newsize;i++)
{
temparray[i] = list[i];
}
size = newsize;
delete [] list;
list = new int[size];
list = temparray;
// this it help see if i made any changes
cout << sizeof(temparray) << "temp size:\n";
cout << sizeof(list) << "list size:\n";
cout << size << "new size:\n\n\n";
}
I want it to output the size of array is the function each time it changes size.I know this can be done with vectors but I would like to understand how to do it with arrays
what can I do differently to make this happen.
You can't: the C++ Standard provides no mechanism to access dynamic array dimensions. If you want to know them, you have to record them when creating the array, then look at the variables you set (much as you've got size hanging around for printing at the end of your program.
Problems in your code:
Problem 1
The following for loop accesses list using out of bound indices. Number of element in list is size, not newSize.
for (int i = 0 ; i < newsize;i++)
{
temparray[i] = list[i];
}
You need to change the conditionals to i < size;.
Then, you need to figure out how how to initialize the rest of the items in temparray.
Problem 2
The following lines cause a memory leak.
list = new int[size];
list = temparray;
You allocate memory using new and immediately lose that pointer in the second line.
Answer to your question
To print the new size, you can use:
cout << "new size: " << size << "\n";
However, I wouldn't recommend putting such code in that function. You are making your class dependent on std::cout for not much benefit, IMO.
I'm hoping someone can shed some light on where I am going wrong with pointers.. I've read countless web pages and tried various things but for some reason my code is returning jibberish (which I'm guessing may be the memory addresses instead of the data within my array). The purpose of the program is to create an array of 100 elements on the heap, pass this array by a pointer to a function (along with two integer variables start and end); a new array will be created on the heap (this comprises of a chunk of the original array using the start and end variables) and the pointer to this array is passed back to the main method so that the new array can be outputted. My problem is not only is the output seeming to be the location not the value, but also it seems 100 values are outputted not 20 as should be expected. I've spent hours trying to figure out where I have gone wrong and just when I think I understand the concept of pointers my faith is destroyed by red squigglies and incorrect outputs. Please HELP! My code is as follows:
#include "stdafx.h"
#include <iostream>
#include <time.h>
using namespace std;
double* getSubArray(double*, int, int);// Declare a function that will get the sub array
int _tmain(int argc, _TCHAR* argv[])
{
const int size = 100;// Declare the size of the array
double* pA;// Declare the variable to hold the pointers to the data in array
double* pB;
int start = 15;
int end = 35;
pA = new double[size];// Create space for the array
srand(clock());// Seed the program to the computers current time so that random gets a different set of random numbers everytime it is run
// Use a for loop to traverse through each element of the array (starting at index 0) placing a number defined by the random function that is no higher than 250
for (int i = 0; i < size; i++)
{
pA[i] = rand()%250;
}
cout << "An Array of 100 numbers is created and stored in the heap, these values are:" << endl;
// Output the Array for the user to see
for (int j = 0; j < size; j++)
{
// Place 10 numbers on each line
if (j % 10 == 0)
{
cout << endl;
}
cout << *(pA + j) << " ";
}
cout << endl << "The program will build a second array using the data between the indexes " << start << " & " << end << endl;
pB = getSubArray(pA, start, end);// Pass the data to the method
// Output second array for user to compare
for (int k = 0; k < size; k++)
{
// Place 10 numbers on each line
if (k % 10 == 0)
{
cout << endl;
}
cout << *(pB + k) << " ";
}
system("pause");
return 0;
}
double* getSubArray(double* pA, int start, int end)
{
double* pB = new double[end-start];// Declare space in the heap for the new array whoes size is the size of the criteria given
for (int i = 0; i < (end - start); i++)
{
for (int j = start; j < end; j++)
{
*(pB + 0) = pA[j];
}
}
return pB;
}
*(pB + 0) = pA[j];
That keeps writing to the first element of the array. Surely you want to write to each element in turn:
for (int i = start; i < end; ++i) {
pB[i-start] = pA[i];
}
or if you don't want to write your own loop
std::copy(pA+start, pA+end, pB);
Don't forget to delete[] everything you new[] or, to save mucking around with low-level memory management, use std::vector to manage the dynamic arrays for you.
I am working on a homework assignment with a few specific requirements. There must be a class named TestScores that takes an array of scores as its argument. It throws an exception if any scores are negative or greater than 100. Finally, it must have a member function that returns an average for all the scores. I wasn't clever enough to find a way to only pass the array into the constructor, so I also added in an int that tells the size of the array.
Running the code (I haven't even gotten around to testing the exceptions yet), I keep getting a Segmentation fault error. Valgrind and gdb have been rather unhelpful, outputting messages like:
==9765== Jump to the invalid address stated on the next line
==9765== at 0x2200000017: ???
Even more mysteriously (to me at least), in the for loop in the client code, my incrementor, i, somehow gets bumped from 0 to a seemingly random two-digit number right after creating the TestScores object. In previous versions, before I started using rand() to populate the array, i just never incremented and did the infinite loop thing.
Here's the contents of TestScores.cpp:
#include <iostream>
using std::cout;
using std::endl;
#include "TestScores.h"
#include <stdexcept>
using std::runtime_error;
// Constructor.
TestScores::TestScores(int a[], int s):
_SIZE(s), _scores()
{
// Look at each item in a[], see if any of them are invalid numbers, and
// only if the number is ok do we populate _scores[] with the value.
for (int i = 0; i < _SIZE; ++i)
{
if (a[i] < 0)
{
throw runtime_error ("Negative Score");
}
else if (a[i] > 100)
{
throw runtime_error ("Excessive Score");
}
_scores[i] = a[i];
cout << _scores[i] << " ";
}
cout << endl;
}
// Finds the arithmetic mean of all the scores, using _size as the number of
// scores.
double TestScores::mean()
{
double total = 0;
for (int i = 0; i < _SIZE; ++i)
{
total += _scores[i];
}
return total / _SIZE;
}
// median() creates an array that orderes the test scores by value and then
// locates the middle value.
double TestScores::median()
{
// Copy the array so we can sort it while preserving the original.
int a[_SIZE];
for (int i = 0; i < _SIZE; ++i)
{
a[i] = _scores[i];
}
// Sort the array using selection sort.
for (int i = 0; i < _SIZE; ++i)
{
int min = a[i];
for (int j = i + 1; j < _SIZE; ++j)
{
if (a[j] < min)
{
min = a[j];
a[j] = a[i];
a[i] = min;
}
}
}
// Now that array is ordered, just pick one of the middle values.
return a[_SIZE / 2];
}
And here's the client code:
#include <iostream>
#include "TestScores.h"
#include <stdexcept>
#include <cstdlib>
#include <ctime>
using std::exception;
using std::cout;
using std::endl;
int main()
{
const int NUM_STUDENTS = 20,
NUM_TESTS = 4;
int test [NUM_TESTS][NUM_STUDENTS];
// Make random seed to populate the arrays with data.
unsigned seed = time(0);
srand(seed);
// Populate the scores for the individual tests graded for the semester.
// These will all be values between 0 and 100.
for (int i = 0; i < NUM_TESTS; ++i)
{
for (int j = 0; j < NUM_STUDENTS; ++j)
{
test[i][j] = rand() % 100;
cout << test[i][j] << " ";
}
cout << endl;
}
// Now we have the data, find the mean and median results for each test.
// All values should be valid, but we'll handle exceptions here.
for (int i = 0; i < NUM_TESTS; ++i)
{
cout << "For Test #" << i + 1 << endl;
try
{
cout << "i = " << i << endl; // i = 0 here.
TestScores results(test[i], NUM_STUDENTS);
cout << "i = " << i << endl; // i = some random number here.
cout << "Mean: " << results.mean() << endl;
cout << "Median:" << results.median() << endl << endl;
}
catch (exception &e)
{
cout << "Error, invalid score: " << e.what() << endl;
}
cout << "For Test #" << i + 1 << endl;
}
return 0;
}
Edit:
The header was requested as well:
#ifndef TEST_SCORES_H
#define TEST_SCORES_H
class TestScores
{
private:
const int _SIZE;
int _scores[];
public:
// Constructor
TestScores(int a[], int);
double mean() const,
median() const;
};
#endif
I played around with making the array dynamic, and didn't initialize the array as empty, which fixed my problems, so that's what I ended up turning in. That leads me to a few follow-up questions.
Before going dynamic, I played around with initializing the array, _scores, by trying to give it the size value that was supposed to already be initialized. This led to compiler problems. I talked with my teacher about that, and he said that you can't allocate space for an array unless there's a hardwired global constant. That is, you can't pass a size value in the constructor to initialize an array. Is that true, and if so, why?
Stepping back a bit, it seems to me that dynamic arrays are better if you need a lot of values, because then you don't need a contiguous block of space in memory. So if you are making small arrays, it seems like a waste of space and time typing to make dynamic arrays. Is this untrue? Should I be doing all arrays from now on as dynamic? This experience certainly changed my opinion on the utility of regular arrays, at least as they pertain to classes.
Also, though I got full credit on the assignment, I feel like I violated the spirit by passing an argument for size (since the literal problem statement reads: "The class constructor should accept an array of test scores as its argument"). Aside from a hardwired global constant or having a size argument, is there a way to pass just the array? I swear I spent a good hour trying to think of a way to do this.
It seems you don't initialize _scores at all. You need _scores = new int[s]; at the top of the constructor (and also delete[] s; in the destructor).
Without initializing _scores, you write things to undefined memory locations.
Without TestScores.h one has to guess, but given what you say about the value of i being corrupted in the loop where you're creating the TestScores objects, that points to your _scores member variable not being properly initialized and when you're trying to load it you are actually trashing memory.
Once TestScores.h is visible, I'll revisit this answer taking the file into account.
Updated now that TestScores.h is available.
The problem is that you are not initializing _scores. You are not actually allocating any memory to hold the array, let alone setting the pointer to point to that memory. So when you attempt to store things into the array you're just trashing memory somewhere.
The first line in your constructor should be:
_scores = new int[_SIZE];
That will allocate memory to hold _SIZE ints and set _scores to point to that memory. Then your assignments to _scores[i] will actually go into defined memory belonging to your program.
Of course, you also have to release this memory (C++ won't do it for you) when instances of TestScore get destroyed. So you will need to define and implement a destructor for TestScores and that destructor needs to contain the line:
delete [] _scores;
This will free the block of memory that _scores points to. You can read docs on the delete operation to see why the [] have to be there in this case.