Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following struct and main function:
struct myStruct{
string name;
int id;
int group;
};
int main(){
myStruct student[5]; // The struct student has an array of 5 elements
search(student, 1, 33); // We pass the struct student with all the 5 elements
}
I want to pass a struct to the function search, and then make an array pointer that stores the value of a certain attribute, but of all the arrays of the struct.
*e is pointing to student, with all the arrays(5), so if type equals 1 the pointer is going to point to all the values of the attribute of each array of the structure e
void search(myStruct *e, int type, int value){
if (type == 1) int *ptr[] = e[0]->id; //An int pointer because the id is an int
if (type == 2) int *ptr[] = e[0]->group;
for (int i = 0; i < 5; i++){
if(*ptr[i] == value){
cout << e[i]->name << endl;
cout << e[i]->id << endl;
cout << e[i]->group << endl;
}
}
}
I want *ptr[] pointing to each array of the attribute depending on the parameter passed in type. Ex:
if ( type == 1 )
ptr[0] = e[0].id;
ptr[1] = e[1].id;
ptr[2] = e[2].id;
ptr[3] = e[3].id;
ptr[4] = e[4].id;
^Notice that is just the id
if ( type == 2 )
ptr[0] = e[0].group;
ptr[1] = e[1].group;
ptr[2] = e[2].group;
ptr[3] = e[3].group;
ptr[4] = e[4].group;
^Notice that is just the group
The problem is that I can't find a way to do that, the real struct in my program has more than just three attributes, it actually has eight, so it will be a waste of code if I do a case for each one.
Thanks for your help.
One way to do this is to make a "pointer to member". Note: This isn't an array of pointers, but rather a pointer that you can only use with an object of the class.
Also note: this is reasonably advanced, so you might want to get normal pointers straight in your head first.
void search(myStruct *e, int type, int value) {
int myStruct::*ptr; // ptr is a pointer to a member variable of an object
if (type == 1) ptr = &myStruct::id;
if (type == 2) ptr = &myStruct::group;
for (int i = 0; i < 5; i++){
if (e[i].*ptr == value){ // access the value of the current object using ptr.
cout << e[i].name << endl; // Note that you had these accesses wrong.
cout << e[i].id << endl;
cout << e[i].group << endl;
}
}
}
A very hack approach that is somewhat low-level and only applies to POD struct type whose attributes are of the same type (e.g., int) and stored continuously.
Suppose your struct looks like this:
struct myStruct {
string name;
int attr1;
int attr2;
...
int attr8;
}
You can write your search function as follow:
void search(myStruct *e, int type, int value) {
int *ptr[5];
for (int i = 0; i < 5; ++i) {
int *base = &e[i].attr1; // treat attr1...attr8 as an int array
ptr[i] = &base[type - 1];
if (*ptr[i] == value) {
cout << e[i].name << endl;
for (int j = 0; j < 8; ++j) {
cout << base[j] << endl;
}
}
}
}
Related
I am trying to write a function that swap two arrays in O(1) time complexity. However, when i try to write the function parameters, I get the error:
error: cannot convert ‘int (*)[4]’ to ‘int**’
Here is my code:
#include <iostream>
using namespace std;
void swap_array_by_ptr(int* a[], int* b[]) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr[] = {1,2,3,4};
int rv[] = {4,3,2,1};
swap_array_by_ptr(&fr, &rv);
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
}
However, when i tried to define the arrays with 'new' command, this works as expected as below:
#include <iostream>
using namespace std;
void swap_array_by_ptr(int** a, int** b) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr = new int[4]{1,2,3,4};
int rv = new int[4]{4,3,2,1};
swap_array_by_ptr(&fr, &rv);
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
}
Is there any way that i can define the arrays with [] method and swap the arrays by sending these arrays with '&array' method ?
As I believe, there must be a way to do that, I only achieve this when I'm trying to do with 'new' method. However, is there any way to swap two arrays in O(1) complexity with sending parameters as
swap_array_by_ptr(&fr, &rv);
?
Thanks for help.
You can not swap two arrays with O( 1 ). You need to swap each pairs of corresponding elements of two arrays.
In the first program
int fr[] = {1,2,3,4};
int rv[] = {4,3,2,1};
swap_array_by_ptr(&fr, &rv);
the expressions &fr and &rv have type int( * )[4] while the corresponding function parameters in fact has the type int **
void swap_array_by_ptr(int* a[], int* b[]) {
after adjusting the parameters having array types to pointers to the array element types by the compiler.
So the compiler issues an error.
You could use standard function std::swap declared in the header <utility> the following way
std::swap( fr, rv );
But in any case its complexity is O( n ).
In the second program there are at least typos. Instead of
int fr = new int[4]{1,2,3,4};
int rv = new int[4]{4,3,2,1};
you have to write
int *fr = new int[4]{1,2,3,4};
int *rv = new int[4]{4,3,2,1};
In this case you are not swapping arrays themselves. That is the arrays will still store their initial values. You are swapping pointers that point to the dynamically allocated arrays.
To be sure that arrays are not swapped consider the following demonstration program.
#include <iostream>
using namespace std;
void swap_array_by_ptr(int** a, int** b) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr[] = { 1,2,3,4};
int rv[] = {4,3,2,1};
int *p1 = fr;
int *p2 = rv;
swap_array_by_ptr( &p1, &p2 );
for (int i = 0; i < 4 ; i++) {
cout << p1[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << p2[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
cout << endl;
}
It is a syntactic quirk inherited from C that a declaration of a function parameter as an array is automatically converted to a declaration as a corresponding pointer. This is not as odd as it might first seem, however, because it dovetails with the automatic conversion of function arguments of array type to corresponding pointers, also inherited from C.*
Thus, this declaration ...
void swap_array_by_ptr(int* a[], int* b[]) {
... is equivalent to this one:
void swap_array_by_ptr(int **a, int **b) {
. But the arguments you are passing do not match. This, for example,
int fr[] = {1,2,3,4};
declares fr as an array of 4 int. If it were passed as a function argument, it would be automatically converted to a pointer to the first element, thus of type int *. Types int * and int ** are not compatible.
On the other hand, what you actually try to pass, &fr is the address of an array 4 int, of type int(*)[4]. This also is incompatible with int **, because arrays are not pointers.
You could write your function like this:
void swap_array_by_ptr(int (*a)[4], int (*b)[4]) {
int temp[4];
memcpy(temp, a, sizeof(a));
memcpy(a, b, sizeof(b));
memcpy(b, temp, sizeof(temp));
}
That would be compatible with the call in your code. Do note, however, that that is specific to array size 4, and you're not really gaining anything useful from that. You could, however, convert it to a template:
template<class T, std::size_t n>
void swap_array(T (*a)[n], T (*b)[n]) {
T temp[n];
memcpy(temp, a, sizeof(a));
memcpy(a, b, sizeof(b));
memcpy(b, temp, sizeof(temp));
}
That handles arrays of any element type and size,** as long as the sizes match. Of course, it scales as O(N) with array size, in both time and auxiliary space.
Such time scaling is unavoidable. To swap two objects you need to read each at least once and write each at least once, and that requires time proportional to the size of the objects. But you could reduce the space overhead to O(1) by swapping the arrays element by element in a loop. That would very likely be slower, but the time complexity would still be O(N).
Of course, you can also use std::swap() on arrays. It is quite similar to the template above, but uses references to the arrays instead of pointers to them.
*This is a specific case of a much more general behavior.
**So long as the temporary array does not turn out to be too large for the stack.
Change the swap_array_by_ptr function from 'swap_array_by_ptr(int** a, int** b)'
to 'swap_array_by_ptr(int* a, int* b)'.
void swap_array_by_ptr(int* a, int* b) {
int* temp = *a;
*a = *b;
*b = temp;
}
here's a link to a similar question: Swapping 2 arrays in C
I'm practicing in order to better understand dynamic arrays and using them in a class. However, I'm struggling to call my functions inside the class. I have no issue with my int size variable, but my int myArray variable is giving me problems. I get the error "expected a member name" when I try to call my void functions in my main function. Are arrays not allowed to be used in this situation?
#include <iostream>
using namespace std;
class myClass
{
public:
int size;
int* myArray = new int[size];
void storeData(int& size, int (&myArray)[]);
void printData(int& size, int(&myArray)[]);
};
void myClass::storeData(int& size, int(&myArray)[])
// Stores array data.
{
cout << "Enter Size of the array: ";
cin >> size;
// User determines array size.
for (int x = 0; x < size; x++)
{
cout << "Array[" << x << "]: ";
cin >> myArray[x];
// User determines array values.
cout << endl;
}
}
void myClass::printData(int &size, int(&myArray)[])
// Displays values of the array.
{
cout << "Value of the arrays are: ";
for (int x = 0; x < size; x++)
{
cout << myArray[x] << " ";;
}
delete[]myArray;
}
int main()
{
myClass object;
object.storeData(object.size, object.(&myArray)[]);
// E0133 expected a member name.
object.printData(object.size, object.(&myArray)[]);
// E0133 expected a member name.
}
There are a couple issues here, I will try to address all of them.
When passing an array to a function, never use [] syntax. In C and C++, arrays decay to pointers, so we do not need [] nor &.
This is valid syntax to pass an array:
int my_array [] = {1,2,3,4};
my_function(my_array, 4);
...
void my_function(int * array, size_t size)
{
//Iterate over the array or do something...
}
In addition, if a function exists within a class, it can access class members freely, meaning we do not have to pass them in at all. See the following change to your code:
void myClass::storeData(int size)
// Stores array data. We do NOT need a pointer to the object array, we already have it!
{
cout << "Enter Size of the array: ";
cin >> size;
// User determines array size.
for (int x = 0; x < size; x++)
{
cout << "Array[" << x << "]: ";
cin >> myArray[x];
// User determines array values.
cout << endl;
}
}
Lastly, dynamic sized arrays must be allocated dynamically. Do not use int* myArray = new int[size]; in your class definition, because size is not yet initialized. Instead, use a constructor or use your store_data function to allocate the memory.
class myClass
{
public:
size_t size;
int * myArray; //Do not allocate anything here...
myClass(size_t size)
{
this->size = size;
myArray = new int[size];
}
};
You can get the size however you want, via user input, etc. and pass this to the constructor or an allocator function like storeData.
I keep getting this error when I try to pass this array of structures into the function AthleticContest():
cannot convert 'person' to 'person*'
Can someone please tell me what I am doing wrong? Am I passing the wrong thing into the function?
struct person
{
int athletic;
int smarts;
int spirit;
int contestVal;
};
int AthleticContest(person subjects[])
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < 3; hh++)
{
int result = subjects[hh].athletic;
subjects[hh].contestVal = result;
cout << "Contestant # " << (hh+1) << ") " << subjects[hh].contestVal << endl;
}
int winner;
int tempWin = -1;
for (int hh = 0; hh < 3; hh++)
{
if (subjects[hh].contestVal > tempWin)
{
tempWin = subjects[hh].contestVal;
winner = hh;
}
else if (subjects[hh].contestVal == tempWin)
{
if (randomInt() > 4)
winner = hh;
}
}
cout << "Winner is Contestant # " << (winner+1) << endl;
return winner;
}
int main()
{
person subject[10];
subject[0].athletic = 5;
subject[0].smarts = 3;
subject[0].spirit = 1;
subject[1].athletic = 1;
subject[1].smarts = 3;
subject[0].spirit = 5;
subject[1].athletic = 3;
subject[1].smarts = 5;
subject[0].spirit = 1;
AthleticContest(subject[2]);
}
The error
When you call your function in main():
AthleticContest(subject[2]);
you pass as argument a single person, which is the third element of your array (the element with index 2). So the compiler understands that you try to pass this object of type person.
But your function's parameter is declared to be of type array of undetermined size (i.e. person[]). C++ treats such array arguments as if they were a pointer (to their first element), so like person*.
This is why you get this error message: these types are incompatible
The solution
To get rid of this error, a solution would be to pass a pointer to a subject, for example:
AthleticContest(&subject[2]); // passes the pointer to the third element
// or
AthleticContest(subject); // passes the pointer to the first element of the original array
However, be very careful, because your function has a very risky design: you expect the argument to be a pointer to an array of at least 3 consecutive elements. So if you call it with &subject[8], it would try to access subject[10] which would be out of bounds. If you'd call with &subject[2] it would work with garbege information, since you have initalized only the first two elements, and not the 3rd, 4th and 6th.
A better solution
It is not clear, why you do the constest just with 3 elements. A better option would be the caller to say how many contestant shall be used (the caller know the size of the array).
In main():
AthleticContest(subject, 2); // 2 is the number of contestants in array
Your function would be defined as:
int AthleticContest(person subjects[], int participants)
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < participants; hh++)
...
for (int hh = 0; hh < participants; hh++)
...
}
A much better solution
You'd better go for std::vector instead of C++ arrays. They can behave like arrays:
vector<person> subject(2); // create a vector of 2 items
subject[0].athletic = 5;
...
But they are much more convenient because they can have a dynamic size and grow as you add new participants:
person hbolt = {4, 2, 1, 0};
subject.emplace_back (hbolt); // one more participant
AthleticContest(subject);
Your function could get the vector by reference or by value. Let's take by reference, since you intend to modify its content and could possibly want this modified data after the return:
int AthleticContest(vector<person> &subjects)
{
...
}
The big advantage, is that you can always know the size of the vector:
for (int hh = 0; hh < subjects.size(); hh++)
...
Here is an online demo.
Of course, if you don't want to take all the participants in the vector, you'd have to think about your function's argument(s): would you prefer a second argument n and always take the n first elements of the vector ? Or would you prefer n participants but start at an arbitrary offset ? In both case, you'd be wise to check that your indexing never goes out of bounds.
One thing you need to change to compile: You're passing a reference to a single element of the array instead of the array itself.
One more thing you might want to check is to change your signature for AthleticContest() so it'll be the right one in C++ to receive fixed-sized array or person as a parameter.
When fixed to compile, and you're code looks like this:
#include <iostream>
using namespace std;
struct person
{
int athletic;
int smarts;
int spirit;
int contestVal;
};
template <std::size_t size>
int AthleticContest(person (&subjects)[size])
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < 3; hh++)
{
int result = subjects[hh].athletic;
subjects[hh].contestVal = result;
cout << "Contestant # " << (hh+1) << ") " << subjects[hh].contestVal << endl;
}
int winner;
int tempWin = -1;
for (int hh = 0; hh < 3; hh++)
{
if (subjects[hh].contestVal > tempWin)
{
tempWin = subjects[hh].contestVal;
winner = hh;
}
else if (subjects[hh].contestVal == tempWin)
{
if (5 > 4)
winner = hh;
}
}
cout << "Winner is Contestant # " << (winner+1) << endl;
return winner;
}
int main()
{
person subject[10];
subject[0].athletic = 5;
subject[0].smarts = 3;
subject[0].spirit = 1;
subject[1].athletic = 1;
subject[1].smarts = 3;
subject[0].spirit = 5;
subject[1].athletic = 3;
subject[1].smarts = 5;
subject[0].spirit = 1;
AthleticContest(subject);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I'm using a library for an Arduino project that has a function I need to call. This function accepts just one parameter of type const char*. Let's call it foo.
I need to pass some int values to foo, so I convert them first using sprintf. So far so good.
The problem comes when I try to fill an array with int values converted to char and then call foo with each of the values in the array.
I hope this explains the problem better:
#include <iostream>
using namespace std;
// This function cannot be modified because
// is a part of a library
void foo(const char *bar){
cout << "Result: " << bar << endl;
}
int main() {
char *values[10]; // My array of values
char tmp[10]; // Temporary buffer for the int > char conversion
for(int i = 0; i < 10; i++){
int samplevalue = i * 2; // Just a sample value, not important
sprintf(tmp, "%d", samplevalue); // Copy the sample value to the temporary buffer
values[i] = tmp; // Assign the value of the temp var to a position in my values array
cout << values[i] << endl;
}
cout << "==============" << endl;
// Here comes the problem:
for(int i = 0; i < 10; i++){
foo(values[i]);
}
return 0;
}
The output of that code is the following:
0
2
4
6
8
10
12
14
16
18
==============
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
Result: 18
As you can see, all of the Result lines are equal to the last value assigned to the tmp var. I guess it's because each of the values in the values[10] array contains a pointer to the tmp variable instead of its actual value.
What I'd like to have is a different number on each Result line, as in the first for loop.
I guess it's pretty obvious that I'm not even near to be a C++ expert and any help will be highly appreciated.
Thanks!
A char * pointer and an array are not a string. Use std::string instead.
#include <iostream>
using namespace std;
// This function cannot be modified because
// is a part of a library
void foo(const char *bar)
{
cout << "Result: " << bar << endl;
}
int main(void)
{
std::string values[10]; // My array of values
char tmp[10]; // Temporary buffer for the int > char conversion
for (int i = 0; i < 10; i++) {
int samplevalue = i * 2; // Just a sample value, not important
sprintf(tmp, "%d", samplevalue); // Copy the sample value to the temporary buffer
values[i] = tmp; // Assign the value of the temp var to a position in my values array
cout << values[i] << endl;
}
cout << "==============" << endl;
// Here comes the problem:
for (int i = 0; i < 10; i++) {
foo(values[i].c_str());
}
return 0;
}
When using an array, all the pointers in your values array point to tmp, you can check that by looping through values and printing the address like this
fprintf(stdout, "%p\n", values[i]);
So because you sprintf() into tmp all the values, the value that will be printed is always the last one, there is no copy implied in
values[i] = tmp;
that just makes values[i] point to tmp, so when you access values[i] you really access tmp.
With std::string copy occurs.
Also, you should probably use a string stream to write numbers into each values[i] directly, because sprintf() is very dangerous.
Or even better use a real c++ solution like this one,
#include <iostream>
#include <vector>
#include <sstream>
// This function cannot be modified because
// is a part of a library
void foo(const char *bar)
{
std::cout << "Result: " << bar << std::endl;
}
int main(void)
{
std::vector<std::string> values;
for (int i = 0; i < 10; i++) {
values.push_back(std::to_string(2 * i));
std::cout << values[i] << std::endl;
}
std::cout << "==============" << std::endl;
for (size_t i = 0; i < values.size(); i++) {
foo(values[i].c_str());
}
return 0;
}
Note that now, you can change the number of elements in values and you can use it as an array if you need to, just read the documentation for std::vector.
Ok, I finally got to get it working. In Arduino strings are declared as String variable;, and the c_str() function converts a string into a const char *, so I convert the int number to String, and then to const char *:
for(int i = 0; i < 10; i++){
String tmp = String(i * 2);
values[i] = tmp.c_str();
}
And that's it! It works now :)
struct zone {
int a;
double b;
};
zone *abc() {
static zone r[10];
for (int i = 0; i < 10; i++) {
r[i].a = 2 * i;
[r[i].b=0.5*i;
cout << r[i].a << " " << r[i].b << endl;
}
return r;
}
int main() {
zone *PP;
zone P[10];
PP = abc();
for (int i = 0; i < 10; i++) {
P[i] = (PP + i);
cout << "work" << P[i].a << endl;
}
getch();
}
I need to return an array of structs that is formed in a function called by main. I managed to retrieve an array with a pointer, but with struct it doesn't work.
How do I return a struct array?
You are assigning a value of variable with a pointer:
P[i] = (PP + i);
To get a copy of internal value, you need access struct:
P[i] = PP[i];
Would be like this:
#include <iostream>
using namespace std;
struct zone {
int a;
double b;
};
zone *abc() {
static zone r[10];
for (int i = 0; i < 10; i++) {
r[i].a = 2 * i;
r[i].b=0.5*i;
cout << r[i].a << " " << r[i].b << endl;
}
return r;
}
int main() {
zone *PP;
zone P[10];
PP = abc();
for (int i = 0; i < 10; i++) {
P[i] = PP[i];
cout << "work" << P[i].a << endl;
}
}
Your struct contains just digits, however, if it contains strings or pointer, you will need make a deep copy.
Well fairly simple - by using another struct to encapsulate the returned array in order to get over 'C' language limitations.
struct zone {
int a;
double b;
};
struct zone_array_of_10 {
zone arr[10];
};
zone_array_of_10 abc() {
zone_array_of_10 r;
for (int i = 0; i < 10; i++) {
r.arr[i].a = 2 * i;
r.arr[i].b=0.5*i;
cout << r.arr[i].a << " " << r.arr[i].b << endl;
}
return r;
}
int main() {
zone_array_of_10 PP;
PP = abc();
for (int i = 0; i < 10; i++) {
cout << "work" << PP.arr[i].a << endl;
}
getch();
}
It's fact that in 'C' language arrays can't be passed by value. However structures can. So whenever you want to pass the actual content of some array without much hassle - just encapsulate it in a structure.
A cool feature of C++ is the use of references. The best part of references is that they allow you to pass data in an out of a function without copying the data (you are using the same data inside and pass back out). So if you make a function.
Another method is to use a pointer to a pointer. You can pass a pointer pointer or address of a pointer and malloc within the function.
structure* a;
funct(&a);
printf("%s\n", a[0].printfunction());
printf("%s\n", a[1].printfunction());
...
void funct(structure** a, int size){
*a = (structure*)malloc(sizeof(structure) * size);
(*a)[0] = ...
(*a)[1] = ..
(*a)[ size-1] = ...
}
You can access the array outside of the function. Just be sure to free/delete anything you call with malloc/new. The above code can use new I'm just better with c. You can easily pull the malloc outside of the function and just pass in a pointer to the array.
In C, a function can't take or return an array. This is annoying, and I've never heard a good reason given for it. Anyway, C++ fixed this a long time ago, but it never really caught on, for reasons that will become plain in a moment.
Obligatory "for anything larger than a toy application you should strongly reconsider using naked pointers and/or raw arrays!"
C++ introduced references. They are really just syntactic sugar around pointers, but aren't all variables just syntactic sugar around pointers? In C++, a function can take and/or return a reference to an array. Like so:
int takes (char (&arr)[10])
{
std::cout << sizeof(arr); // 10
}
int (&returns())[10]
{
return some_array; // Not a pointer!
}
int (&takes_and_returns (int (&arr)[10])) [10]
{
return arr;
}
Of course, I don't have to tell you that this is extremely ugly and difficult to read. Modern C++ to the rescue!
template <size_t n, typename T>
using array<n,t> = T[n];
int takes (array<10,int>& arr);
array<10,int>& returns();
array<10,int>& takes_and_returns (array<10,int>& arr);
Note, however, that due to the way new works, it is an ordeal to properly construct and then return a reference to a dynamic array. This is how I did it, but I'm not even sure if this is correct; there might lurk some UB:
int (&returns())[10]
{
int* x = new int[10];
return *(int(*)[10]) x;
}
Of course, we can tidy this up a bit:
using arr10 = int[10];
arr10& returns()
{
int* x = new int[10];
return *(arr10*) x;
}
And then, at the call site, you'd assign it to a reference like so:
int (&my_array)[10] = returns();
// doing stuff ...
delete[] &my_array;
As you can see, at the end of the day, getting all this to work correctly and to interoperate with existing features is a bit of an ordeal. If you need a function to take or return an array, this is how you do it. But for most purposes, it is better (easier, safer) to use standard library containers.