Iterate over struct pointer - c++

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.

Related

C++ Segmentation fault while dereferencing a void pointer to a vector

#include <iostream>
#include <vector>
#include <mutex>
struct STRU_Msg
{
std::string name;
void *vpData;
};
class CMSG
{
public:
template <typename T>
int miRegister(std::string name)
{
STRU_Msg msg;
msg.name = name;
msg.vpData = malloc(sizeof(T));
msgtable.push_back(msg);
std::cout << "registeratio ok\n";
return 0;
}
template <typename T>
int miPublish(std::string name, T tData)
{
for (int i = 0; i < msgtable.size(); i++)
{
if (!name.compare(msgtable[i].name))
{
(*(T *)msgtable[i].vpData) = tData;
std::cout << "SUccess!\n";
return 0;
}
else
{
std::cout << "cannot find\n";
return 0;
}
}
}
private:
std::vector<STRU_Msg> msgtable;
};
int main()
{
CMSG message;
std::string fancyname = "xxx";
std::vector<float> v;
// message.miRegister< std::vector<float> >(fancyname);
// for (int i = 0; i < 1000; i++)
// {
// v.push_back(i);
// }
// std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
// message.miPublish< std::vector<float> >(fancyname, v);
for (int i = 0; i < 1000; i++)
{
v.push_back(i);
}
std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
message.miRegister< std::vector<float> >(fancyname);
message.miPublish< std::vector<float> >(fancyname, v);
return 0;
}
What I want to achieve is to write a simple publish/subscribe (like ROS) system, I use void pointer so that it works for all data type. This is the simplified code.
If I publish an int, it works fine, but what really confuse me are:
If I pass a long vector (like this code), it gave me the
"segmentation fault (core dump)" error.
If I define the vector between "register" and "publish" (i.e. like
the commented part), this error goes away.
If I use a shorter vector, like size of 10, no matter where I define
it, my code run smoothly.
I use g++ in Linux.
Please help me fix my code and explain why above behaviors will happen, thanks in ahead!
You cannot copy std::vector or any other non-trivial type like that. Before you do anything (even assignment-to) with such an object, you need to construct it using a constructor and placement new.
A way to do this would be
new(msgtable[i].vpData) T;
Do this in the register function.
Then you can assign a value as you do.
Still better, do not use malloc at all, allocate your object with (normal, non-placement) new.
I however strongly suggest ditching void* and moving to a template based implementation of STRU_Msg. If you don't feel like reinventing the wheel, just use std::any.

Class accept and return array

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?

C++ code improvement, array out of bounds

This is a class template for an Array. I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue. The print outs work well, except if it falls out of range, the compiler enables the range by default and it displays a 6 digit number.
Perhaps looking for a better way to initialize the arrays with the appropriate element number for a better check and if it does fall out of range when looking up the element, display an error.
// implement the class myArray that solves the array index
// "out of bounds" problem.
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
template <class T>
class myArray
{
private:
T* array;
int begin;
int end;
int size;
public:
myArray(int);
myArray(int, int);
~myArray() { };
void printResults();
// attempting to overload the [ ] operator to find correct elements.
int operator[] (int position)
{if (position < 0)
return array[position + abs(begin)];
else
return array[position - begin];
}
};
template <class T>
myArray<T>::myArray(int newSize)
{
size = newSize;
end = newSize-1;
begin = 0;
array = new T[size] {0};
}
template <class T>
myArray<T>::myArray(int newBegin, int newEnd)
{
begin = newBegin;
end = newEnd;
size = ((end - begin)+1);
array = new T[size] {0};
}
// used for checking purposes.
template <class T>
void myArray<T>::printResults()
{
cout << "Your Array is " << size << " elements long" << endl;
cout << "It begins at element " << begin << ", and ends at element " << end << endl;
cout << endl;
}
int main()
{
int begin;
int end;
myArray<int> list(5);
myArray<int> myList(2, 13);
myArray<int> yourList(-5, 9);
list.printResults();
myList.printResults();
yourList.printResults();
cout << list[0] << endl;
cout << myList[2] << endl;
cout << yourList[9] << endl;
return 0;
}
First of all, your operator[] is not correct. It is defined to always return int. You will get compile-time error as soon as you instantiate array of something, that is not implicitly convertible to int.
It should rather be:
T& operator[] (int position)
{
//...
}
and, of course:
const T& operator[] (int position) const
{
//you may want to also access arrays declared as const, don't you?
}
Now:
I overloaded the [ ] operator in hopes it would fix the "out of bounds" issue.
You didn't fix anything. You only allowed clients of your array to define custom boundaries, nothing more. Consider:
myArray<int> yourList(-5, 9);
yourList[88] = 0;
Does your code check for out-of-bounds cases like this one? No.
You should do it:
int operator[] (int position)
{
if((position < begin) || (position > end)) //invalid position
throw std::out_of_range("Invalid position!");
//Ok, now safely return desired element
}
Note, that throwing exception is usually the best solution in such case. Quote from std::out_of_range doc:
It is a standard exception that can be thrown by programs. Some components of the standard library, such as vector, deque, string and bitset also throw exceptions of this type to signal arguments out of range.
An better option to redefining an array class is to use the containers from the std library. Vector and array(supported by c++11). They both have an overloaded operator [] so you can access the data. But adding elements using the push_back(for vector) method and using the at method to access them eliminates the chance or getting out of range errors, because the at method performs a check and push_back resizes the vector if needed.

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;
}
}