I'm sure this is pretty simple, but I couldn't really devise a search query which helped me resolve the issue.
I'd almost be inclined to think this was a bug in the Windows command prompt, except that I've never seen it before, until I started using exceptions, where it occurs if and only if I use exception::what().
This is for a homework assignment, and the program is supposed to compute a series of given problems and display the answers. All of the problems are in a similar vein (matrix/vector arithmetic), and the only ones which cause problems are the problems which are intentionally designed to generate errors, since that's the only time exception::what() is used.
Here's one of the offending problems:
(By the way, is it OK to arbitrarily place these
problems into blocks so that the objects go out of scope and the destructors are called before the next problem, as I've done?)
{ // Problem #9
Vector v1(5);
Matrix m1(3, 3, 1);
try {
v1.set(1, -2);
v1.set(2, -1);
v1.set(3, 4);
v1.set(4, 9);
v1.set(5, 3);
m1.set(1, 1, 12);
m1.set(1, 2, 36);
m1.set(1, 3, -7);
m1.set(2, 1, 4);
m1.set(2, 3, 11);
m1.set(3, 1, 7);
m1.set(3, 2, -5);
m1.set(3, 3, -2);
Vector * ans9 = product(m1, v1);
cout << "Answer to problem 9:" << endl;
ans9->print();
delete ans9;
}
catch(exception & ex) {
cout << "Exception in problem 9: " << ex.what() << endl;
}
} // End problem 9
cout << endl << endl;
The Matrix class and its constructor are nothing special, and the code doesn't throw any exceptions there, so I'll just share the offending product() function:
Vector * product(Matrix &m, Vector &v) {
unsigned int vLength = v.getLength(), mRows = m.getRows(), mCols = m.getCols();
if ( mCols != vLength ) {
throw std::logic_error("matrix/vector product impossible (size mismatch)!");
}
Vector * vprod = new Vector(mRows);
for (unsigned int i = 1; i <= mRows; ++i) {
double value = 0;
for (unsigned int j = 1; j <= vLength; ++j) {
value += (m.get(i, j)) * (v.get(j));
}
vprod->set(i, value);
}
return vprod;
}
And here's an example of the kind of output I get:
I left that ! in there so you can see that it is just printing whatever the last character was right on down that column, until some other character is explicitly printed there.
So, what exactly is going on here? I figure it's probably something to do with string termination, but maybe that's just because I've had too much fun with C in the past.
EDIT: Folks asked for a compilable code segment, and the best I could do was 228 lines. Here goes:
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout;
using std::endl;
using std::exception;
class Vector {
private:
unsigned int length;
double *elements;
public:
Vector(unsigned int desiredLength);
~Vector();
//void dDestroy(Vector &v);
unsigned int getLength();
void set(unsigned int position, double value);
double get(unsigned int position);
void print();
};
Vector::Vector(unsigned int desiredLength) {
length = desiredLength;
elements = new double[length];
for (unsigned int i = 0; i < length; ++i) {
elements[i] = 0;
}
}
Vector::~Vector() {
delete[] elements;
}
unsigned int Vector::getLength() {
return length;
}
void Vector::set(unsigned int position, double value) {
if (position > length || position <= 0) {
throw std::logic_error("vector set failed (out of range)");
}
--position;
elements[position] = value;
}
double Vector::get(unsigned int position) {
if (position > length || position <= 0) {
throw std::logic_error("vector get failed (out of range)");
}
--position;
return elements[position];
}
void Vector::print() {
std::cout << "[ ";
for (unsigned int i=0; i < length; ++i) {
std::cout << elements[i] << " " ;
}
std::cout << "]";
}
class Matrix {
private:
unsigned int rows, cols;
double **elements;
public:
Matrix(unsigned int desiredRows, unsigned int desiredCols, double defaultValue);
~Matrix();
unsigned int getRows();
unsigned int getCols();
void set(unsigned int i, unsigned int j, double value);
double get(unsigned int i, unsigned int j);
void print();
};
Matrix::Matrix(unsigned int desiredRows, unsigned int desiredCols, double defaultValue) {
rows = desiredRows, cols = desiredCols;
// Create
elements = new double*[rows];
for (unsigned int i = 0; i < rows; ++i) {
elements[i] = new double[cols];
}
// Initialize
for (unsigned int i = 0; i < rows; ++i) {
for (unsigned int j = 0; j < cols; ++j) {
elements[i][j] = defaultValue;
}
}
}
Matrix::~Matrix() {
for (unsigned int i = 0; i < rows; ++i) {
delete[] elements[i];
}
delete[] elements;
}
unsigned int Matrix::getRows() {
return rows;
}
unsigned int Matrix::getCols() {
return cols;
}
void Matrix::set(unsigned int i, unsigned int j, double value) {
if (i > rows || j > cols) {
throw std::logic_error("matrix set failed (out of range).");
}
--i, --j;
elements[i][j] = value;
}
double Matrix::get(unsigned int i, unsigned int j) {
if (i > rows || j > cols || i <= 0 || j <= 0) {
throw std::logic_error("matrix get failed (out of range).");
}
--i, --j;
return elements[i][j];
}
void Matrix::print() {
// TODO it would be nice to format based on maximum digits in any value
for (unsigned int i = 0; i < rows; ++i) {
std::cout << "[ ";
for (unsigned int j = 0; j < cols; ++j) {
std::cout << std::setprecision(2) << elements[i][j] << " ";
}
std::cout << "]\n";
}
}
Vector * dot(Vector &v1, Vector &v2) {
if (v1.getLength() != v2.getLength() ) {
throw std::logic_error("dot product impossible (length mismatch)");
}
double result = 0;
for (unsigned int i = 1; i <= v1.getLength(); ++i) {
result += (v1.get(i) * v2.get(i));
}
Vector * vdot = new Vector(1);
vdot->set(1, result);
return vdot;
}
Vector * product(Matrix &m, Vector &v) {
unsigned int vLength = v.getLength(), mRows = m.getRows(), mCols = m.getCols();
if ( mCols != vLength ) {
throw std::logic_error("matrix/vector product impossible (size mismatch)");
}
Vector * vprod = new Vector(mRows);
for (unsigned int i = 1; i <= mRows; ++i) {
double value = 0;
for (unsigned int j = 1; j <= vLength; ++j) {
value += (m.get(i, j)) * (v.get(j));
}
vprod->set(i, value);
}
return vprod;
}
Vector * dot(Vector &v1, Vector &v2);
Vector * product(Matrix &m, Vector &v);
int main() {
cout << endl;
{ // Problem #1
Vector v1(3), v2(3);
try {
v1.set(1, 2);
v1.set(2, 1);
v1.set(3, 3);
v2.set(1, 0);
v2.set(2, 4);
v2.set(3, -9);
Vector * ans1 = dot(v1, v2);
cout << "Answer to problem 1:" << endl;
ans1->print();
delete ans1;
}
catch(const exception & ex) {
cout << "Exception in problem 1: " << ex.what() << endl;
}
} // End problem 1
cout << endl << endl;
{ // Problem #2
Vector v1(2), v2(3);
try {
v1.set(1, 12);
v1.set(2, 1);
v2.set(1, 3);
v2.set(2, -1);
v2.set(3, 5);
Vector * ans2 = dot(v1, v2);
cout << "Answer to problem 2:" << endl;
ans2->print();
delete ans2;
}
catch(const exception & ex) {
cout << "Exception in problem 2: " << ex.what() << endl;
}
} // End problem 2
cout << endl << endl;
}
OK, the comments get a bit crowed and the following is a little to explicit for a comment anyway, so please forgive the not-exactly-an-answer-style of the following.
Since the extra "!" also apears in the line with the prompt, after the program has already exited, it is rather unlikely, that it has something to do with your application. It could be a faulty display driver, or some issue with the Client Server Runtime Sub System / Process (csrss.exe) or the Console Windows Host (conhost.exe), which provide the window when you run console applications.
Also, if the screenshot is not missleading, it looks like the superflous characters (especially visible for the closing parenthesis from "problem 6") are not even fully repeated, but only partial. I.e. the character is somehow "cut".
Anyway, there are some steps you could try to further investigage the problem:
Does it only happen on your system?
Does it only happen with 64bit processes (I assume your having one from the CMD title)
Does it also happen if you're not actually throwing the exception, e.g.
std::logic_error err("blah");
std::cout << err.what() << std::endl;
Can you change your program to use stdio instead of iostreams? And does it still happen then.
Try to redirect the output of the program to a file (e.g. "myapp.exe > foo.txt"). Does the file also contain the extra "!".
I have seen such a behavior under totally different circumstances.
Example:
printf("12345678901234567890\r"); /* carriage return, but no linefeed */
printf("ABCDEFGHIJ\n");
This should output:
ABCDEFGHIJ1234567890
But then, I don't see anything like that (iostreams vs. stdio or not) in your code.
It worries me that you catch 'exception &' instead of 'const exception &'. 'ex' might actually refere to an object that has already been destroyed, so the what() method returns garbage. You must ensure that the 'ex' parameter in your catch-handler, referes to a valid copy of the object originally thrown.
Related
For my "basics of programming" project i was ordered to make a "memory game". 2 players in their respective turns choose which cards to reveal on a "m x n" sized board. "m" and "n" are to be chosen at the start of each game. My question is, how can I create an array of structures used to display the board a the moment of user's input. So far I just used a const int to create an array of a maximum size, however more than 95% of the arrays indexes are empty using this method. Is there a way to create the array right after user's input while also having those functions defined and declared with an array of structures that's the size of the input? Here's my code so far:
const int MAX_M = 1000;
const int MAX_N = 1000;
Karta Plansza2[MAX_M][MAX_N];
void SprawdzanieParzystosci(int& m, int& n);
void RozmiaryTablicy(int& m, int& n);
void generuj(int m, int n, Karta Plansza[MAX_M][MAX_N]);
void WyswietleniePlanszy(int m, int n, Karta Plansza[MAX_M][MAX_N]);
void generuj(int m, int n, Karta Plansza[][MAX_N])
{
srand((unsigned int)time(NULL));
char A;
int B;
int C;
int D;
int k = 0;
int w1, w2, k1, k2;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
Plansza[i][j].WartoscKarty = 0;
}
while (k < (m*n))
{
A = char(rand() % 10 + 65);
B = (rand() % 10);
C = (rand() % 10);
D = ((rand() % 2000000) + 1);
do{
w1 = rand() % m;
k1 = rand() % n;
}while(Plansza[w1][k1].WartoscKarty != 0);
Plansza[w1][k1].ZnakPierwszy = A;
Plansza[w1][k1].LiczbaPierwsza = B;
Plansza[w1][k1].LiczbaDruga = C;
Plansza[w1][k1].WartoscKarty = D;
k++;
do{
w2 = rand() % m;
k2 = rand() % n;
} while (Plansza[w2][k2].WartoscKarty != 0);
Plansza[w2][k2].ZnakPierwszy = A;
Plansza[w2][k2].LiczbaPierwsza = B;
Plansza[w2][k2].LiczbaDruga = C;
Plansza[w2][k2].WartoscKarty = D;
k++;
}
}
/////////////////////////////////////////////////////
void WyswietleniePlanszy(int m, int n, Karta Plansza[MAX_M][MAX_N])
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
cout << "***" << setw(5);
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].ZnakPierwszy << "*" << " ";
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].LiczbaPierwsza << "*" << " ";
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].LiczbaDruga << "*" << " ";
cout << "\n";
// for(int j = 0; j < 10; j++)
// cout << wzor[i][j].num4 << " ";
for (int j = 0; j < n; j++)
cout << "***" << setw(5);
cout << "\n";
cout << endl;
}
}
/////////////////////////////////////////////////////
void RozmiaryTablicy(int& m, int& n)
{
cout << "Podaj rozmiar m tablicy: ";
cin >> m;
cout << "Podaj rozmiar n tablicy: ";
cin >> n;
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
void SprawdzanieParzystosci(int& m, int& n)
{
while ((m * n) % 2 != 0 || (m <= 0) || (n <= 0)) {
RozmiaryTablicy(m, n);
if((m * n) % 2 != 0 || (m <= 0) || (n <= 0)) cout << "Zle dane. Prosze podac dane jeszcze raz" << endl;
}
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
int main()
{
int m =1;
int n =1;
SprawdzanieParzystosci(m, n);
generuj(m,n,Plansza2);
WyswietleniePlanszy(m,n,Plansza2);
cout << m << endl;
cout << n << endl;
system("pause");
return 0;
}
For example, If the user inputs m = 5 an n = 6 it would create an Plansza[5][6] array instead of a Plansza[1000][1000] array
Quick hack of a board, remark the nice board[row][column] notation and the returned reference to the field. C++17 (might work in C++14)
#include <iostream>
#include <memory>
#include <cstring>
using DaType = char;
class Board {
int rows = 0;
int cols = 0;
std::unique_ptr<DaType[]> board; // RAII
public:
class Row {
DaType *board;
public:
Row(DaType *row) : board(row) {}
DaType& operator[](int col) { return board[col]; }
};
Board(int row, int col) : rows(row), cols(col), board(std::make_unique<DaType[]>(row*col)) { memset(board.get(), '.', rows*cols); }
Row operator[](int row) { return Row(board.get()+row*cols); }
};
int main() {
const int sx = 6, sy = 10;
Board board(sx,sy);
board[3][5] = 'x';
for (int i = 0; i < sx; ++i ) {
for (int j = 0; j < sy; ++j )
std::cout << board[i][j];
std::cout << '\n';
}
}
Ps. it seemed simpler last time I did this ...
Update thanks to IlCapitano
class Board {
int rows = 0;
int cols = 0;
std::unique_ptr<DaType[]> board; // RAII
public:
Board(int row, int col) : rows(row), cols(col), board(std::make_unique<DaType[]>(row*col)) { memset(board.get(), '.', rows*cols); }
DaType *operator[](int row) { return board.get()+row*cols; }
};
The easiest way to solve this would be to just use std::vector, since the size of arrays in arguments, stackallocations, etc. has to be known at compile-time.
The easiest option without using vector would be to declare Plansza2 as a Karta* and allocate the memory dynamically after SprawdzanieParzystosci using Plansza2 = new Karta[m*n]; (Don't forget to call delete[](Plansza2); before ending your program). If you do this you can access the cells with Plansza2[y * m + x] (assuming m is width and n is height). The advantage of mapping the 2-dimensional array to a 1 dimensional array by placing all rows after one another is that you only need one allocation and one deletion, and furthermore it improves cache-friendliness.
A cleaner way to solve this (removing the possibility for a memory leak if something throws an exception or you forget to call delete) would be to create your own class for 2-dimensional arrays, that would call new[] in the constructor and delete[] in the destructor. If you do that you could define Karta& operator()(int x, int y); and const Karta& operator()(int x, int y) const; to return the appropriate cell, allowing you to access a cell with dynamicMap(x, y). operator[] can only take one argument and is therefor more complicated to use to access a 2-dimensional array (you can for example take an std::pair as the argument or return a proxy-class that also has operator[] defined). However if you write your own destructor, you need to take care of the copy-(always) and move-(c++11 onwards) constructors and assignment operators, since the default instantiations would lead to your destructor trying to delete the same pointer multiple times. An example for a move-assignment operator is:
DynamicMap& DynamicMap::operator=( DynamicMap&& map ){
if(this == &map)
return *this; //Don't do anything if both maps are the same map
dataPointer = map.dataPointer; //Copy the pointer to "this"
map.dataPointer = nullptr; //Assign nullptr to map.dataPointer because delete[] does nothing if called with null as an argument
//You can move other members in the above fashion, using std::move for types more complex than a pointer or integral, but be careful to leave map in a valid, but empty state, so that you do not try to free the same resource twice.
return *this;
}
The move constructor doesn't require the if-clause at the start, but is otherwise identical and the copy-constructor/assignment operator should probably declared as = delete; since it will probably be a bug if you copy your map. If you do need to define the copy operations, do not copy the pointer but instead create a new array and copy the contents.
Pointers are still a little confusing to me. I want the split function to copy negative elements of an array into a new array, and positive elements to be copied into another new array. A different function prints the variables. I've included that function but I don't think it is the problem. When the arrays are printed, all elements are 0:
Enter number of elements: 5
Enter list:1 -1 2 -2 3
Negative elements:
0 0
Non-Negative elements:
0 0 0
I assume that the problem is that in the split function below i need to pass the parameters differently. I've tried using '*' and '**' (no quotes) for passing the parameters but I get error messages, I may have done so incorrectly.
void split(int alpha[], int bravo[], int charlie[], int aSize, int bSize, int cSize) {
int a = 0;
int b = 0;
for (int i = 0; i < aSize; ++i) {
if (alpha[i] < 0) {
alpha[i] = bravo[a];
++a;
}
else {
alpha[i] = charlie[b];
++b;
}
}
if (a + b != aSize) {
cout << "SOMETHING HAS GONE HORRIBLY WRONG!";
exit(0);
}
}
my main function (all arrays are required to be pointers):
int num_elements;
cin >> num_elements;
int * arr1 = new int[num_elements];
int x;
cout << "Enter list:";
for (int i = 0; i < num_elements; ++i) {
cin >> x;
arr1[i] = x;
}
int y = 0;
int z = 0;
count(arr1, num_elements, y, z);
int * negs = new int [y];
int * nonNegs = new int[z];
split(arr1, negs, nonNegs, num_elements, y, z);
cout << "Negative elements:" << endl;
print_array(negs, y);
cout << endl;
cout << "Non-Negative elements:" << endl;
print_array(nonNegs, z);
cout << endl;
All functions:
void count(int A[], int size, int & negatives, int & nonNegatives) {
for (int i = 0; i < size; ++i) {
if (A[i] < 0) {
++negatives;
}
if (A[i] >= 0) {
++nonNegatives;
}
}
}
void split(int alpha[], int bravo[], int charlie[], int aSize, int bSize, int cSize) {
int a = 0;
int b = 0;
for (int i = 0; i < aSize; ++i) {
if (alpha[i] < 0) {
alpha[i] = bravo[a];
++a;
}
else {
alpha[i] = charlie[b];
++b;
}
}
if (a + b != aSize) {
cout << "SOMETHING HAS GONE HORRIBLY WRONG!";
exit(0);
}
}
void print_array(int A[], int size) {
for (int i = 0; i < size; ++i) {
cout << A[i] << " ";
}
}
All help is appreciated.
EDIT: I apologize for my unclear question, I was wondering how to get my arrays to behave as I want them to.
Array is behaving correctly as per instruction :), you are doing minor mistake (may be overlook) in split function. I have commented out the statement and given reason of problem, please correct those two line of code, rest is fine.
void split(int alpha[], int bravo[], int charlie[], int aSize, int bSize, int cSize) {
int a = 0;
int b = 0;
for (int i = 0; i < aSize; ++i) {
if (alpha[i] < 0) {
//alpha[i] = bravo[a];// here alpha is your source array, don't overwrite it
bravo[a] = alpha[i];
++a;
}
else {
//alpha[i] = charlie[b];// here alpha is your source array, don't overwrite it
charlie[b] = alpha[i];
++b;
}
}
if (a + b != aSize) {
cout << "SOMETHING HAS GONE HORRIBLY WRONG!";
exit(0);
}
}
The code is supposed to create a 2d array fill it with some values then put the values into 1d array and add
**I have this function called AddTab that should add the 2d array to 1d array.
#include "pch.h"
#include <iostream>
using namespace std;
int **createTab(int n, int m)
{
int **tab = nullptr;
try {
tab = new int *[n];
}
catch (bad_alloc)
{
cout << "error";
exit(0);
}
for (int i = 0; i < n; i++)
{
try {
tab[i] = new int[m] {};
}
catch (bad_alloc)
{
cout << "error";
exit(0);
}
}
return tab;
}
void FillTab(int m, int n, int **tab)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cin >> tab[i][j];
}
}
}
void AddTab(int **tab,int n,int m)
{
int *temp_tab=new int[m];
memset(temp_tab, 0, sizeof(temp_tab));
for (int i=0;i<m;i++)
{
for (int j=0;j<n;j++)
{
temp_tab[j] += tab[i][j];
cout << temp_tab[j] << "( " << j << ")" << endl;
}
}
}
int main()
{
int **X = nullptr;
X = createTab(3, 3);
FillTab(3, 3, X);
AddTab(X, 3, 3);
}
I filled the 3x3 2d tab with 1's.
For the first loop it was supposed to be {1,1,1} but instead something weird pops up.
1( 0)
-842150450( 1)
-842150450( 2)
2( 0)
-842150449( 1)
-842150449( 2)
3( 0)
-842150448( 1)
-842150448( 2)
What can I do so it will work fine?
sizeof(temp_tab)
for
int *temp_tab
returns 4/8 bytes, it depends on system. So only first 4/8 bytes are set to 0 for your dynamic allocated array. If temp_tab[j] is not set to 0, by doing temp_tab[j] += tab[i][j]; you update garbage value and finally as result you get garbage value as well.
Fix:
memset(temp_tab, 0, sizeof(int) * m);
I am writing a program that displays integer arrays. I set the size of the array, but I am wondering how I can ask the user the index of the array that they want listed. Say the const SIZE = 10, and the user wants to see the first three in the array. I want to also write an exception that catches the error if the user input is over the size of the array. If you need to see some code, let me know. Any help is appreciated!
intergerarray.h
class IntArray
{
private:
int *aptr; // Pointer to the array
int arraySize; // Holds the array size
void subscriptError(); // Handles invalid subscripts
public:
class OutOfBoundException
{
public:
int index;
OutOfBoundException(){};
int getInde() { return index; }
};
IntArray(int); // Constructor
IntArray(const IntArray &); // Copy constructor
~IntArray(); // Destructor
int size() const // Returns the array size
{
return arraySize;
}
int &operator[](const int &); // Overloaded [] operator
};
IntergerArray.cpp
IntArray::IntArray(int s)
{
arraySize = s;
aptr = new int[s];
for (int count = 0; count < arraySize; count++)
*(aptr + count) = 0;
}
IntArray::IntArray(const IntArray &obj)
{
arraySize = obj.arraySize;
aptr = new int[arraySize];
for (int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
IntArray::~IntArray()
{
if (arraySize > 0)
delete[] aptr;
}
void IntArray::subscriptError()
{
cout << "ERROR: Subscript out of range.\n";
exit(0);
}
int &IntArray::operator[](const int &sub)
{
if (sub < 0 || sub >= arraySize)
subscriptError();
return aptr[sub];
}
driver file.cpp
int main()
{
int SIZE = 10;
//int index;
//cout << "enter an index";
//cin >> index;
IntArray table(SIZE);
for (int x = 0; x < SIZE; x++)
table[x] = x;
for (int x = 0; x < SIZE; x++)
cout << table[x] << " ";
cout << endl;
//table[SIZE + 1] = 0;
return 0;
}
Isn't this what you are trying to do? why so much code for such a simple problem?
const int arraySize = 10;
int array[arraySize];
int elementToDis;
do
{
std::cout << "Number of array elements to display: ";
std::cin >> elementToDis;
} while (elementToDis > arraySize || elementToDis < 0); // this is your exeption
for (int ccc(0); ccc < elementToDis; ++ccc)
std::cout << "Index " << ccc << ": " << array[ccc] << '\n';
I think you want to display all elements lower than an index value entered by the user :
Let array[] be the array name of size=10,you can get an index value (say l) from the user and use that value inside a for loop for printing all elements in index lower than l
int array[size]
void disp_in(int l)
{
if(l>=size) // if l greater than or equal to size (as index start at 0)
throw l;
else
{
cout<<"Elements : ";
for(int i=0;i<=l;i++) //if we have say l=2 ,array values in indexes 0,1and 2 will be displayed
cout<<array[i];
}
}
int main ()
{
int l;
cout<<"Enter index : ";
cin>>l; //till this index value, the array value will be displayed
try
{
disp_in(l);
}
catch(int e)
{
cout<<"Index value greater than max index";
}
return 0;
}
You could try something like this:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
void print_numbers( const std::vector<int>& array, int nNumbers, const char* pszSeparator )
{
if ( nNumbers > static_cast<int>(array.size()) )
{
throw std::exception();
}
std::copy( array.begin(), array.begin() + nNumbers, std::ostream_iterator<int>( std::cout, pszSeparator ) );
}
int main()
{
std::vector<int> array( 10 );
//Just for testing
{
int n = 0;
auto generator = [n]() mutable
{
return n++;
};
std::generate_n( array.begin(), array.size(), generator );
}
try
{
print_numbers(array, 11, "\n");
}
catch ( std::exception e )
{
std::cout << "Error message..." << std::endl;
}
return 0;
}
I have a 2D array and I want to define a function that returns the value of the index that the user gives me using operator overloading.
In other words:
void MyMatrix::ReturnValue()
{
int row = 0, col = 0;
cout << "Return Value From the last Matrix" << endl;
cout << "----------------------------------" << endl;
cout << "Please Enter the index: [" << row << "][" << col << "] =" << ((*this).matrix)[row][col] << endl;
}
The operation ((*this).matrix)[row][col] should return an int.
I have no idea how to build the operator [][].
Alternatively, I could concatenate a couple of calls to the operator [], but I didn't succeed in it, because the first call to that operaror will return int* and the second one will return int, and it compel to build another operator, and I dont want to do that.
The data matrix is defined like
int** matrix; matrix = new int*[row];
if (matrix == NULL)
{
cout << "Allocation memory - Failed";
}
for (int i = 0; i < row; i++)//Allocation memory
{
matrix[i] = new int[col];
if (matrix[i] == NULL)
{
cout << "Allocation memory - Failed";
return;
}
}
What can I do?
Thank you,
Simply, such an operator does not exist, so you can not overload it.
A possible solution is to define two classes: the Matrix and the Row.
You can define the operator[] of a Matrix so that it returns a Row, then define the same operator for the Row so that it returns an actual value (int or whatever you want, your Matrix could be also a template).
This way, the statement myMatrix[row][col] will be legal and meaningful.
The same can be done in order to assign a new Row to a Matrix or to change a value in a Row.
* EDIT *
As suggested in the comments, also you should take in consideration to use operator() instead of operator[] for such a case.
This way, there wouldn't be anymore the need for a Row class too.
You can define your own operator [] for the class. A straightforward approach can look the following way
#include <iostream>
#include <iomanip>
struct A
{
enum { Rows = 3, Cols = 4 };
int matrix[Rows][Cols];
int ( & operator []( size_t i ) )[Cols]
{
return matrix[i];
}
};
int main()
{
A a;
for ( size_t i = 0; i < a.Rows; i++ )
{
for ( size_t j = 0; j < a.Cols; j++ ) a[i][j] = a.Cols * i + j;
}
for ( size_t i = 0; i < a.Rows; i++ )
{
for ( size_t j = 0; j < a.Cols; j++ ) std::cout << std::setw( 2 ) << a[i][j] << ' ';
std::cout << std::endl;
}
}
The program output is
0 1 2 3
4 5 6 7
8 9 10 11
I have no idea how to build the operator [][].
Sometimes it is fine to use a different operator, namely ():
int& Matrix::operator () (int x, int y)
{
return matrix[x][y];
}
const int& Matrix::operator () (int x, int y) const
{
return matrix[x][y];
}
int diagonal (const Matrix& m, int x)
{
return m (x, x); // Usage.
}
Advantage:
No need to use "intermediate" class like Row or Column.
Better control than with Row& Matrix operator (int); where someone could use the Row reference to drop in a row of, say, illegal length. If Matrix should represent a rectangular thing (image, matrix in Algebra) that's a potential source of error.
Might be less tedious in higher dimensions, because operator[] needs classes for all lower dimensions.
Disadvantage:
Uncommon, different syntax.
No more easy replacement of complete rows / columns, if that's desired. However, replacing columns is not easy, anyway, provided you used rows to model (and vice versa).
In either case, there are pros and cons if the number of dimensions are not known at runtime.
I was looking for self-tested array replacement...
Improved version returns reference or NULL reference and checks boundaries inside.
#include <iostream>
#include <iomanip>
template<typename T, int cols>
class Arr1
{
public:
Arr1(T (&place)[cols]) : me(place) {};
const size_t &Cols = cols;
T &operator [](size_t i)
{
if (i < cols && this != NULL) return me[i];
else {
printf("Out of bounds !\n");
T *crash = NULL;
return *crash;
}
}
private:
T (&me)[cols];
};
template<typename T, int rows, int cols>
class Arr2
{
public:
const size_t &Rows = rows;
const size_t &Cols = cols;
Arr2() {
ret = NULL;
for (size_t i = 0; i < rows; i++) // demo - fill member array
{
for (size_t j = 0; j < cols; j++) matrix[i][j] = cols * i + j;
}
}
~Arr2() {
if (ret) delete ret;
}
Arr1<T, cols>(&operator [](size_t i))
{
if (ret != NULL) delete ret;
if (i < rows) {
ret = new Arr1<T, cols>(matrix[i]);
return *ret;
}
else {
ret = NULL;
printf("Out of bounds !\n");
return *ret;
}
}
//T(&MemberCheck)[rows][cols] = matrix;
private:
T matrix[rows][cols];
Arr1<T, cols> *ret;
};
template<typename T,int rows, int cols>
class Arr
{
public:
const size_t &Rows = rows;
const size_t &Cols = cols;
T(&operator [](size_t i))[cols]
{
if (i < rows) return matrix[i];
else {
printf("Out of bounds !\n");
T(*crash)[cols] = NULL;
return *crash;
}
}
T (&MemberCheck)[rows][cols] = matrix;
private:
T matrix[rows][cols];
};
void main2()
{
std::cout << "Single object version:" << endl;
Arr<int, 3, 4> a;
for (size_t i = 0; i <= a.Rows; i++)
{
int *x = &a[i][0];
if (!x) printf("Fill loop - %i out of bounds...\n", i);
else for (size_t j = 0; j < a.Cols; j++) a[i][j] = a.Cols * i + j;
}
for (size_t i = 0; i < a.Rows; i++)
{
for (size_t j = 0; j <= a.Cols; j++) {
std::cout << std::setw(2) << a[i][j] << ' ';
if (a.MemberCheck[i][j] != a[i][j])
printf("Internal error !");
}
std::cout << std::endl;
}
std::cout << endl << "Double object version:" << endl;
Arr2<int, 3, 4> a2;
for (size_t i = 0; i < a2.Rows; i++)
{
for (size_t j = 0; j <= a2.Cols; j++) {
int &x = a2[i][j];
if (&x)
{
x++;
std::cout << std::setw(2) << a2[i][j] << ' ';
//if (&a2.MemberCheck[i][j] != &a2[i][j])
// printf("Internal error !");
}
}
}
}
Output
Single object version:
Out of bounds !
Fill loop - 3 out of bounds...
0 1 2 3 4
4 5 6 7 8
8 9 10 11 -858993460
Double object version:
1 2 3 4 Out of bounds !
5 6 7 8 Out of bounds !
9 10 11 12 Out of bounds !
it works fine in the program below
#include<iostream>
using namespace std;
class A{
public:
int r,c;
int** val;
A()
{
r=0;c=0;val=NULL;
}
A(int row,int col)
{
r=row;c=col;
int count=0;
val=new int*[row];
for(int i=0;i<r;i++){
val[i]=new int[col];
for(int j=0;j<c;j++){
count++;
val[i][j]=count;
}
}
}
int* &operator[](int index){
return val[index];
}
};
int main(void){
A a(3,3);
cout<<a[1][2];
return 0;
}
here, a[1][2] first computes a[1]-->which returns 2nd row as (int*) type
then it's read as (int*)[2] which returns 3rd element of that row.In short,
a[1][2]------>(a[1])[2]------>(val[1])[2]------>val[1][2].