Class accept and return array - c++

I try to create a class that accept and return an array but I got some problem. I'm not sure if it is legal to return an array from a class. Or it could be done by returning an pointer to the array. Thank for any solution to the problem.
#include <iostream>
using namespace std;
class myclass {
private:
int Array[10];
public:
myclass (int temp[10]) {
for (int i = 0; i < 10; i++) {
Array [i] = temp [i];
}
}
int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
int* returnArray2 () {
return this->Array; // hope it will return a pointer to the array
}
};
int main () {
int Array[10] = {1,2,3,4,5,6,7,8,9};
myclass A(Array);
cout << A.returnArray() << endl; // try to return an array and print it.
myclass* ptr = &A;
cout << *ptr->returnArray2 << endl; // error here
return 0;
}

First of all it is better to write the constructor either like
myclass ( const int ( &temp )[10] ) {
for (size_t i = 0; i < 10; i++) {
Array [i] = temp [i];
}
}
or like
myclass ( int temp[], size_t n ) : Array {} {
if ( n > 10 ) n = 10;
for (size_t i = 0; i < n; i++) {
Array [i] = temp [i];
}
}
Or even you may define the both constructors.
As for the returning value then you may not return an array. You may return either a reference to an array or a pointer to the entire array or a pointer to its first element
For example
int ( &returnArray () )[10] {
return Array;
}
In this case you can write in main
for ( int x : A.returnArray() ) std::cout << x << ' ';
std::cout << std::endl;
As for this statement
cout << *ptr->returnArray2 << endl; // error here
then you forgot to place parentheses after returnArray2. Write
cout << *ptr->returnArray2() << endl;
And the following member function is wrong because the expression in the return statement has type int * while the return type of the function is int
int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
So either the function will coincide with the the second member function if you specify its return type like int *. Or you could change the return expression to *Array

int returnArray () {
return Array; // error here, I'm not sure if it is legal to return an array.
}
This is illegal because Array is not of int type. Your returnArray2 is valid, however. As for this line:
cout << *ptr->returnArray2 << endl; // error here
This is illegal because returnArray2 is a function; you must call it to return the int*:
cout << *ptr->returnArray2() << endl; // prints the first value in the array
Other notes:
Your capitalization is backwards; you should call your class MyClass and your member array arr or arr_, or you will confuse a lot of people.
return this->Array; this is redundant, you can simply return Array;
If you haven't heard of std::vector and std::array you should research those, as they are generally superior to C-style arrays.

In general, I would suggest to read a c++ book to get your basics correct as there are lot of issues in the code you posted.
Regarding your main question about exposing C style arrays in class public API, this is not a very robust mechanism. Do it if it is absolutely essential because of existing code but if possible prefer to use std::vector. You will mostly always end up with better code.
Other answers have corrected your coding errors, so i won't repeat that.
One other thing, your code suggests that the array size is fixed. You can pass and return the array by reference as well. Refer to: General rules of passing/returning reference of array (not pointer) to/from a function?

Related

Iterate over struct pointer

Given a struct pointer to the function. How can I iterate over the elements and do not get a segfault? I am now getting a segfault after printing 2 of my elements. Thanks in advance
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
struct something{
int a;
string b;
};
void printSomething(something* xd){
while(xd){
cout<<xd->a<<" "<<xd->b<<endl;
xd++;
}
}
int main()
{
something m[2];
m[0].a = 3;
m[0].b = "xdxd";
m[1].a = 5;
m[1].b = "abcc";
printSomething(m);
return 0;
}
You'll have to pass the length of the array of struct
void printSomething(something* xd, size_t n){
//^^^^^^^^ new argument printSomething(m, 2);
size_t i = 0;
while(i < n){ // while(xd) cannot check the validity of the xd pointer
cout<<xd->a<<" "<<xd->b<<endl;
xd++;
i++;
}
}
You should better use std::vector<something> in C++
The problem is that you are assuming there is a nullptr value at the end of the array but this is not the case.
You define a something m[2], then
you take the address of the first element, pointing to m[0]
you increase it once and you obtain address to m[1], which is valid
you increase it again, adding sizeof(something) to the pointer and now you point somewhere outside the array, which leads to undefined behavior
The easiest solution is to use a data structure already ready for this, eg std::vector<something>:
std::vector<something> m;
m.emplace_back(3, "xdxd");
m.emplace_back(5, "foo");
for (const auto& element : m)
...
When you pass a pointer to the function, the function doesn't know where the array stops. After the array has decayed into a pointer to the first element in the array, the size information is lost. xd++; will eventually run out of bounds and reading out of bounds makes your program have undefined behavior.
You could take the array by reference instead:
template <size_t N>
void printSomething(const something (&xd)[N]) {
for (auto& s : xd) {
std::cout << s.a << " " << s.b << '\n';
}
}
Now xd is not a something* but a const reference to m in main and N is deduced to be 2.
If you only want to accept arrays of a certain size, you can make it like that too:
constexpr size_t number_of_somethings = 2;
void printSomething(const something (&xd)[number_of_somethings]) {
for (auto& s : xd) {
std::cout << s.a << " " << s.b << '\n';
}
}
int main() {
something m[number_of_somethings];
// ...
printSomething(m);
}
Another alternative is to pass the size information to the function:
void printSomething(const something* xd, size_t elems) {
for(size_t i = 0; i < elems; ++i) {
std::cout << xd[i].a << " " << xd[i].b << '\n';
}
}
and call it like this instead:
printSomething(m, std::size(m));
Note: I made all versions const something since you are not supposed to change the element in the `printSomething´ function.

Through what to call the method, if I already created constructor with initialization of array of structures?

I'm trying to call the method displayChoices, member of the class MachineManager through the object of the class. But I already have a constructor with initializing of the array of structures. How I understood when we create an object of the class compiler implicitly create a default constructor of the class.
Question: How to call method displayChoices?
#include "MachineManager.h"
using namespace std;
int main()
{
MachineManager mjp;
mjp.displayChoices();
return 0;
}
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};
class MachineManager {
static const int Num_Drinks = 3; /// why it works only with static?!!!
BrewInfo* BrewArr[Num_Drinks];
public:
MachineManager()
{
*BrewArr[0]->Cost = 1.25;
*BrewArr[0]->Number = 20;
*BrewArr[1]->DrinkName = "pepsi";
*BrewArr[1]->Cost = 1.15;
*BrewArr[1]->Number = 17;
*BrewArr[2]->DrinkName = "Aloe";
*BrewArr[2]->Cost = 2.00;
*BrewArr[2]->Number = 15;
};
int displayChoices();
}
int MachineManager::displayChoices() // (which displays a menu of drink names and prices)
{
cout << 1;
int choice;
cout << "|1." << *BrewArr[0]->DrinkName << " |2." << *BrewArr[1]->DrinkName << " |3." << *BrewArr[2]->DrinkName << " |" << endl;
cin >> choice;
if (!choice || choice == 0) {
system("slc");
displayChoices();
}
else
return choice;
}
displayChoices has to print a menu in console.
You have a majo bug in your source code. You do not yet understand, how pointer work.
You are defining an array of pointer with BrewInfo* BrewArr[Num_Drinks];.
But these pointers are not initialized. They point to somewhere. Then you are dereferencing those pointers (pointing to somewhere) and assigning a value to somewhere in the memory.
This is a major bug.
The array dimensions for C-Sytle arrays must be a compile time constant.
You cannot write
int x=3;
unt array[x];
This is C99 code (called VLA, Variable length array), but not C++.
Solution for you problem:
Do never use C-Style arrays, like int array[5]. Use STL container like std::vector instead.
Do not use pointers.
This is your major problem. Define your array with BrewInfo BrewArr[Num_Drinks];. Please remove also the pointer from
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};

After passing pointer to the main function, cannot print the content properly

I am practicing using pointers to create objects and access data. I created a stuct called BigNum to represent a number with multiple digits. When I try to print the content of the struct inside the readDigits function, it can be printed pretty well. However, after passing the pointer to the main function, the content of the stuct is printed out to be random numbers. Why? How to fix it?
struct BigNum{
int numDigits; //the number of digits
int *digits; //the content of the big num
};
int main(){
BigNum *numPtr = readDigits();
for (int i=0; i<(numPtr->numDigits);i++ ){
std::cout << (numPtr->digits)[i] << std::endl;
}
return 0;
}
BigNum* readDigits(){
std::string digits;
std::cout << "Input a big number:" << std::endl;
std::cin >> digits;
int result[digits.length()];
toInt(digits,result);
BigNum *numPtr = new BigNum();
numPtr->numDigits = digits.length();
numPtr->digits = result;
/* When I try to print in here, it's totally okay!
std::cout << "Here is the content:" << std::endl;
for (int i=0; i<numPtr->numDigits;i++ ){
std::cout << (numPtr->digits)[i] << std::endl;
}
*/
return numPtr;
}
void toInt(std::string& str, int result[]){
for (int i=0;i<str.length() ;i++ ){
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
BigNum* readDigits(){
//....
int result[digits.length()];
//....
numPtr->digits = result;
return numPtr;
}
result is stored on the stack. So if you return it as part of numPtr, it will be invalid as soon as you exit the function. Instead of storing it on the stack you have to allocate it with new.
You have undefined behavior because you assign address of automatic object to digits pointer. When readDigits() returns this memory is not valid anymore. You should assign to this pointer address of heap-based object (or some equivalent, e.g. use vector or smart pointer):
#include <vector>
struct BigNum{
int numDigits; //the number of digits
std::vector<int> digits; //the content of the big num
};
Then you can insert numbers into vector this way:
int input;
while ( std::cin >> input) //enter any non-integer to end the loop
{
digits.push_back(input);
}
The problem is that within the function BigNum* readDigits() you assign apointer to stack memory to the pointer of your newly allocated BigNum:
int result[digits.length()]; // <--- variable is on the stack!!!
toInt(digits,result);
BigNum *numPtr = new BigNum();
numPtr->numDigits = digits.length();
numPtr->digits = result; // <--- make pointer to stack memory available to caller of readDigits
Now if you proceed the access to numPtr->digits is ok since the memory of result is still valid on the stack (as long as you are within readDigits). Once you've left ´readDigits()´ the memory of result is overwritten depending on what you do (calling other functions, ...).
Right now I'm even wondering why you don't get a compiler error with ´int result[digits.length()];´ since ´digits.length()´ is not constant and the size of required stack memory has to be defined at compile time... so I'm thinking that the size of result is actually 0...?? Would be a nice thing to test!
My recommendation is to modify the code of readDigits as follows:
BigNum* readDigits()
{
std::string digits;
int i;
std::cout << "Input a big number:" << std::endl;
std::cin >> digits;
//int result[digits.length()];
//toInt(digits,result);
BigNum *numPtr = new BigNum();
numPtr->numDigits = digits.length();
numPtr->digits = (int *)malloc(sizeof(int) * numPtr->numDigits); // allocate heap memory for digits
toInt(digits, numPtr->digits);
/* When I try to print in here, it's totally okay!
std::cout << "Here is the content:" << std::endl;
for (i = 0; i <numPtr->numDigits; i++)
{
std::cout << (numPtr->digits)[i] << std::endl;
}
*/
return numPtr;
}
Remember to free your memory if ´BigNum *numPtr´ is no longer used (´free(numPtr->digits);´) otherwise you'll get a memory leak (sooner or later):
int main()
{
BigNum *numPtr = readDigits();
int i;
for (i = 0; i < (numPtr->numDigits); i++)
{
std::cout << (numPtr->digits)[i] << std::endl;
}
free(numPtr->digits); // free memory allocated by readDigits(..)
return 0;
}

Random array value after return c++

My problem is I don't know what happens with data that I put into my arrays and how to make them stay in array. While debugging it is clear that arr gets initialized with zeros and arr2 with {1,2,3}. Functions however return some random values.. can someone help me to point out what it should be like?
#include <iostream>
#include <algorithm>
#include <vector>
class A
{
private:
double arr[5];
public:
A()
{
std::fill( arr, arr + 5, 0.0 );
};
~A() {};
void setArr( double arrx[] )
{
for ( int i = 0; i < 5; i++ )
arr[i] = arrx[i];
}
double* getArr(void) { return arr;}
};
int* probe()
{
int arr2[3] = {1,2,3};
return arr2;
}
int main()
{
A ob1;
double rr[5] = {1,2,3,4,5};
ob1.setArr(rr);
std::cout << ob1.getArr() << std::endl;
std::cout << probe() << std::endl;
system("Pause");
}
EDIT:
Now thanks to you i realize I have to loop the get** function to obtain all values. But how can I loop it if my planned usage is to write it like you see below into some file?
pF = fopen ("myfile.csv","a");
if (NULL != pF)
{
char outp[1000];
sprintf_s(outp, 1000, "%6d,\n", ob1.getArr());
fputs(outp, pF);
fclose(pF);
}
In
std::cout << ob1.getArr() << std::endl;
std::cout << probe() << std::endl;
You are actually printing the pointers (address), not the values which are double or int. You need to loop through all the elements of the array to print them.
As pointed out by P0W that accessing element of probe() has undefined behaviour, in that case you must make sure that the array should be valid. One quick solution is that declare the array static in the function.
As you want to write the value in the file
pF = fopen ("myfile.csv","a");
if (NULL != pF)
{
char outp[1000];
int i;
int retsofar=0;
for(i=0;i<5;++i)
retsofar+=sprintf_s(outp+retsofar, 1000-retsofar, "%6d,\n", ob1.getArr()[i]);
fputs(outp, pF);
fclose(pF);
}
you are trying to print the addresses of arrays returned by ob1.getArr() and probe() methods. Every time you are getting different addresses. If you want to print array, use loop.
In probe(), you are creating an array on stack and simply returning it's pointer. It is not safe. When it goes out of scope, its values can be overwritten and you may get un expected behaviour. So create that array on heap.

How to access the element of a list/vector that passed by reference in C++

The problem is passing lists/vectors by reference
int main(){
list<int> arr;
//Adding few ints here to arr
func1(&arr);
return 0;
}
void func1(list<int> * arr){
// How Can I print the values here ?
//I tried all the below , but it is erroring out.
cout<<arr[0]; // error
cout<<*arr[0];// error
cout<<(*arr)[0];//error
//How do I modify the value at the index 0 ?
func2(arr);// Since it is already a pointer, I am passing just the address
}
void func2(list<int> *arr){
//How do I print and modify the values here ? I believe it should be the same as above but
// just in case.
}
Is the vectors any different from the lists ? Thanks in advance.
Any links where these things are explained elaborately will be of great help. Thanks again.
You aren't passing the list by reference, but by a pointer. In "C talk" the two are equal, but since there is a reference type in C++, the distinction is clear.
To pass by reference, use & instead of * - and access "normally", i.e.
void func(list<int>& a) {
std::cout << a.size() << "\n";
}
To pass by pointer, you need to derefer the pointer with an asterisk (and do take note of operator presedence), i.e.
void func(list<int>* arr) {
std::cout << (*a).size() << "\n"; // preferably a->size();
}
There is no operator[] in std::list.
//note the return type also!
void func1(list<int> * arr)
{
for (list<int>::iterator i= arr->begin() ; i!= arr->end(); i++ )
{
//treat 'i' as if it's pointer to int - the type of elements of the list!
cout<< *i << endl;
}
}
In your example, return type of func1() is not specified. So I specified it. You may change from void to some other type. Also don't forget to specify return type for func2() and main() too.
If you want to use subscript operator [], then you've to use std::vector<int>, as list<> doesn't overload operator[]. In that case, you can write :
for(std::vector<int>::size_type i = 0 ; i < arr->size() ; i++ )
{
cout << (*arr)[i] << endl;
}
I'm still assuming arr is pointer to vector<int>.
Maybe, you would like to modify your code a little bit, like this:
void func1(vector<int> & arr) // <-- note this change!
{
for(std::vector<int>::size_type i = 0 ; i < arr.size() ; i++ )
{
cout << arr[i] << endl;
}
}