Swap arrays by using pointers in C++ - c++

I have two arrays of pointers to doubles that I need to swap. Rather than just copy the data within the arrays, it would be more efficient just to swap the pointers to the arrays. I was always under the impression that array names were essentially just pointers, but the following code receives a compiler error:
double left[] = {1,2,3};
double right[] = {9,8,7};
double * swap = left;
left = right; // Error "ISO C++ forbids assignment of arrays"
right = swap; // Error "incompatible types in assignment of `double*' to `double[((unsigned int)((int)numParameters))]'"
Creating the arrays dynamically would solve the problem, but can't be done in my application. How do I make this work?

double array_one[] = {1,2,3};
double array_two[] = {9,8,7};
double *left = array_one;
double *right = array_two;
double * swap = left;
left = right;
right = swap;
Works nicely.
edit:
The definitions array_one and array_two shouldn't be used and the double*left and double*right should be as public as your original left and right definitions.

Arrays are not the same as pointers and cannot be swapped in the way you describe. To do the pointer swap trick, you must use pointers, either dynamically allocate the memory, or use pointers to access the data (in the way Daniel has described).

C-style arrays are not pointers, but like most objects, they can be swapped with the standard std::swap():
#include <iostream>
#include <utility>
int main()
{
double array_one[] = {1,2,3};
double array_two[] = {9,8,7};
std::swap(array_one, array_two);
std::cout << "array_one[0] = " << array_one[0] << '\n';
std::cout << "array_two[0] = " << array_two[0] << '\n';
}
Actually, looks like std::swap() for arrays is only defined in C++0x (20.3.2), so nevermind.
The correct answer is, for both arrays in scope and arrays as pointers to first elements:
std::swap_ranges(array_one, array_one + 3, array_two);

One of the easiest ways to convince people that they're not pointers, and not easily swapped, is to show the following code:
struct ex {
char c[4];
double d[3];
};
struct ex a = {"foo", {1.0, 2.0, 3.0} };
struct ex b = {"bar", {6,7,8} };
Now clearly a.d and b.d are arrays. Swapping them will involve hard work, as the array {6,7,8} has to end in memory after a.c=="foo" and that means copying 3 doubles. There's no pointer in the picture.

Try this
double *right = (double[]){9,8,7};
double *left = (double[]){8,2,3};

You can pass both pointers to arrays by references, and in case pointers are not const, you can just swap them:
void swap(char * & first, char * & second)
{
std::swap(first, second);
}

When you declare an array, the name is a pointer, which cannot be altered.
Ex:
int array[10];
int *p;
p = array; // legal
array = p; // illegal; array is a constant pointer which can't be altered.
The only way you can achieve the swap is using new pointers to the array.
This should help you:
SO question on array name as pointer

Related

C++ quicksort with const unsigned** input pointers

I am currently struggling with Pointers in C++, especially with the input of following function:
/*
... there is an immutable array a of unsigned integers that we are not allowed to change
In order to sort this array, a second array b containing pointers to the individual
elements in a is created. We then sort the poiners in b based on the values of the pointed-to elements in a.
(d) implement the quicksort function which sorts an array of pointers as outlined above.
Note that the parameters to this function are two pointers, one to the first element in b and
one to the first element past the end of b.
*/
// Sort the range of pointers [begin; end)
void quicksort(const unsigned** begin, const unsigned** end)
{
//TODO
}
However, the Function is given const values, so is there any way to change the position of the input pointers?
A common Quicksort algorithm relies on the swap function, I tried calling
void swap (const unsigned** a, const unsigned** b){
const unsigned** temp = **a;
**a = **b;
**b = temp;
}
with
swap(begin, (end-1));
in the Quicksort Function. But that does not not work as the value for **a cannot be changed (Here, with the value **b), due to it being const.
So how would I even be able to sort the input pointers if I cannot change their order?
First of all, I know this stuff is really tricky when starting out with c/c++ and I had my fair share of confusion when I did. Therefore I will try to explain it the best way I can:
What you are trying to do in your swap function is changing the actual value of the integers behind the pointers by dereferencing two times and reassigning. You got an array of pointers which is basically a pointer to the first pointer and if you dereference that two times you end up at the actual integers, however you don't want that because this integer is constant.
Instead you want to end up at the pointers to the actual integers and swap those around. You can achieve that by dereferencing only once. If you try to reasign the pointer to change what it's pointing to, you can change the order of the array of pointers without ever touching the actual integers.
your swap function should look like this:
void swap(const unsigned int** a,const unsigned int** b) {
const unsigned int* temp = *a;
*a = *b;
*b = temp;
}
and the code where you call it could look something like this:
const unsigned int sort_without_touching[] = { 1 , 2 };
const unsigned int* ptr_array[] = {&sort_without_touching[0],
&sort_without_touching[1]};
//1 2
std::cout << *ptr_array[0] << " " << *ptr_array[1] << std::endl;
swap((ptr_array+ 0), (ptr_array+ 1));
//2 1
std::cout << *ptr_array[0] << " " << *ptr_array[1] << std::endl;

SFML returning Vertex array [duplicate]

I am fairly new to C++ and have been avoiding pointers. From what I've read online I cannot return an array but I can return a pointer to it. I made a small code to test it and was wondering if this was the normal / correct way to do this:
#include <iostream>
using namespace std;
int* test (int in[5]) {
int* out = in;
return out;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int* pArr = test(arr);
for (int i = 0; i < 5; i++) cout<<pArr[i]<<endl;
cout<<endl;
return 0;
}
Edit: This seems to be no good. How should I rewrite it?
int* test (int a[5], int b[5]) {
int c[5];
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
int* out = c;
return out;
}
Your code as it stands is correct but I am having a hard time figuring out how it could/would be used in a real world scenario. With that said, please be aware of a few caveats when returning pointers from functions:
When you create an array with syntax int arr[5];, it's allocated on the stack and is local to the function.
C++ allows you to return a pointer to this array, but it is undefined behavior to use the memory pointed to by this pointer outside of its local scope. Read this great answer using a real world analogy to get a much clear understanding than what I could ever explain.
You can still use the array outside the scope if you can guarantee that memory of the array has not be purged. In your case this is true when you pass arr to test().
If you want to pass around pointers to a dynamically allocated array without worrying about memory leaks, you should do some reading on std::unique_ptr/std::shared_ptr<>.
Edit - to answer the use-case of matrix multiplication
You have two options. The naive way is to use std::unique_ptr/std::shared_ptr<>. The Modern C++ way is to have a Matrix class where you overload operator * and you absolutely must use the new rvalue references if you want to avoid copying the result of the multiplication to get it out of the function. In addition to having your copy constructor, operator = and destructor, you also need to have move constructor and move assignment operator. Go through the questions and answers of this search to gain more insight on how to achieve this.
Edit 2 - answer to appended question
int* test (int a[5], int b[5]) {
int *c = new int[5];
for (int i = 0; i < 5; i++)
c[i] = a[i]+b[i];
return c;
}
If you are using this as int *res = test(a,b);, then sometime later in your code, you should call delete []res to free the memory allocated in the test() function. You see now the problem is it is extremely hard to manually keep track of when to make the call to delete. Hence the approaches on how to deal with it where outlined in the answer.
Your code is OK. Note though that if you return a pointer to an array, and that array goes out of scope, you should not use that pointer anymore. Example:
int* test (void)
{
int out[5];
return out;
}
The above will never work, because out does not exist anymore when test() returns. The returned pointer must not be used anymore. If you do use it, you will be reading/writing to memory you shouldn't.
In your original code, the arr array goes out of scope when main() returns. Obviously that's no problem, since returning from main() also means that your program is terminating.
If you want something that will stick around and cannot go out of scope, you should allocate it with new:
int* test (void)
{
int* out = new int[5];
return out;
}
The returned pointer will always be valid. Remember do delete it again when you're done with it though, using delete[]:
int* array = test();
// ...
// Done with the array.
delete[] array;
Deleting it is the only way to reclaim the memory it uses.
New answer to new question:
You cannot return pointer to automatic variable (int c[5]) from the function. Automatic variable ends its lifetime with return enclosing block (function in this case) - so you are returning pointer to not existing array.
Either make your variable dynamic:
int* test (int a[5], int b[5]) {
int* c = new int[5];
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
return c;
}
Or change your implementation to use std::array:
std::array<int,5> test (const std::array<int,5>& a, const std::array<int,5>& b)
{
  std::array<int,5> c;
  for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
  return c;
}
In case your compiler does not provide std::array you can replace it with simple struct containing an array:
struct array_int_5 {
int data[5];
int& operator [](int i) { return data[i]; }
int operator const [](int i) { return data[i]; }
};
Old answer to old question:
Your code is correct, and ... hmm, well, ... useless. Since arrays can be assigned to pointers without extra function (note that you are already using this in your function):
int arr[5] = {1, 2, 3, 4, 5};
//int* pArr = test(arr);
int* pArr = arr;
Morever signature of your function:
int* test (int in[5])
Is equivalent to:
int* test (int* in)
So you see it makes no sense.
However this signature takes an array, not pointer:
int* test (int (&in)[5])
A variable referencing an array is basically a pointer to its first element, so yes, you can legitimately return a pointer to an array, because thery're essentially the same thing. Check this out yourself:
#include <assert.h>
int main() {
int a[] = {1, 2, 3, 4, 5};
int* pArr = a;
int* pFirstElem = &(a[0]);
assert(a == pArr);
assert(a == pFirstElem);
return 0;
}
This also means that passing an array to a function should be done via pointer (and not via int in[5]), and possibly along with the length of the array:
int* test(int* in, int len) {
int* out = in;
return out;
}
That said, you're right that using pointers (without fully understanding them) is pretty dangerous. For example, referencing an array that was allocated on the stack and went out of scope yields undefined behavior:
#include <iostream>
using namespace std;
int main() {
int* pArr = 0;
{
int a[] = {1, 2, 3, 4, 5};
pArr = a; // or test(a) if you wish
}
// a[] went out of scope here, but pArr holds a pointer to it
// all bets are off, this can output "1", output 1st chapter
// of "Romeo and Juliet", crash the program or destroy the
// universe
cout << pArr[0] << endl; // WRONG!
return 0;
}
So if you don't feel competent enough, just use std::vector.
[answer to the updated question]
The correct way to write your test function is either this:
void test(int* a, int* b, int* c, int len) {
for (int i = 0; i < len; ++i) c[i] = a[i] + b[i];
}
...
int main() {
int a[5] = {...}, b[5] = {...}, c[5] = {};
test(a, b, c, 5);
// c now holds the result
}
Or this (using std::vector):
#include <vector>
vector<int> test(const vector<int>& a, const vector<int>& b) {
vector<int> result(a.size());
for (int i = 0; i < a.size(); ++i) {
result[i] = a[i] + b[i];
}
return result; // copy will be elided
}
In a real app, the way you returned the array is called using an out parameter. Of course you don't actually have to return a pointer to the array, because the caller already has it, you just need to fill in the array. It's also common to pass another argument specifying the size of the array so as to not overflow it.
Using an out parameter has the disadvantage that the caller may not know how large the array needs to be to store the result. In that case, you can return a std::vector or similar array class instance.
Your code (which looks ok) doesn't return a pointer to an array. It returns a pointer to the first element of an array.
In fact that's usually what you want to do. Most manipulation of arrays are done via pointers to individual elements, not via pointers to the array as a whole.
You can define a pointer to an array, for example this:
double (*p)[42];
defines p as a pointer to a 42-element array of doubles. A big problem with that is that you have to specify the number of elements in the array as part of the type -- and that number has to be a compile-time constant. Most programs that deal with arrays need to deal with arrays of varying sizes; a given array's size won't vary after it's been created, but its initial size isn't necessarily known at compile time, and different array objects can have different sizes.
A pointer to the first element of an array lets you use either pointer arithmetic or the indexing operator [] to traverse the elements of the array. But the pointer doesn't tell you how many elements the array has; you generally have to keep track of that yourself.
If a function needs to create an array and return a pointer to its first element, you have to manage the storage for that array yourself, in one of several ways. You can have the caller pass in a pointer to (the first element of) an array object, probably along with another argument specifying its size -- which means the caller has to know how big the array needs to be. Or the function can return a pointer to (the first element of) a static array defined inside the function -- which means the size of the array is fixed, and the same array will be clobbered by a second call to the function. Or the function can allocate the array on the heap -- which makes the caller responsible for deallocating it later.
Everything I've written so far is common to C and C++, and in fact it's much more in the style of C than C++. Section 6 of the comp.lang.c FAQ discusses the behavior of arrays and pointers in C.
But if you're writing in C++, you're probably better off using C++ idioms. For example, the C++ standard library provides a number of headers defining container classes such as <vector> and <array>, which will take care of most of this stuff for you. Unless you have a particular reason to use raw arrays and pointers, you're probably better off just using C++ containers instead.
EDIT : I think you edited your question as I was typing this answer. The new code at the end of your question is, as you observer, no good; it returns a pointer to an object that ceases to exist as soon as the function returns. I think I've covered the alternatives.
you can (sort of) return an array
instead of
int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
int* m3 = test(m1, m2);
write
struct mystruct
{
int arr[5];
};
int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
mystruct m3 = test(m1,m2);
where test looks like
struct mystruct test(int m1[5], int m2[5])
{
struct mystruct s;
for (int i = 0; i < 5; ++i ) s.arr[i]=m1[i]+m2[i];
return s;
}
not very efficient since one is copying it delivers a copy of the array

Argmin for static arrays

Hello all I am trying to implement the Argmin function. following the example from one of the comments here ArgMin for vector<double> in C++?, I have written the following logic.
rev_tone = get_rev_tone(cam_model_path);
//reading the images
Mat img_rev = imread("C:/Users/20181217/Desktop/images/imgs/output_rev.png");
Mat ideal = imread("C:/Users/20181217/Desktop/images/imgs/output_fwd_v6.png");
int idx = 256;
int no_of_channels = 3;
float rev_tone_s[256][3];
///dynamic to static conversion
for (int i = 0; i < rev_tone.size(); i++) {
for (int j = 0; j < rev_tone[i].size(); j++) {
rev_tone_s[i][j] = rev_tone[i][j];
}
}
int dist = distance(rev_tone.begin(), std::min_element(rev_tone.begin(), rev_tone.end()));//rev_tone is of type vector<vector<float>>
cout << dist << endl;
int dist_s = distance(rev_tone_s.begin(), std::min_element(rev_tone_s.begin(), rev_tone_s.end())); //rev_tone_s is a static 2d float of type float[256][3]
cout << dist_s << endl;
when i am executing the program, this line is working without any problem.
int dist = distance(rev_tone.begin(), std::min_element(rev_tone.begin(), rev_tone.end()));//rev_tone is of type vector<vector<float>>
But the nature of my project doesn't allow any dynamic memory allocations. so I have converted the Vectors into arrays (float_rev_tone_s). When I try to perform the Argmin() on the converted array in the following line
int dist_s = distance(rev_tone_s.begin(), std::min_element(rev_tone_s.begin(), rev_tone_s.end())); //rev_tone_s is a static 2d float of type float[256][3]
it gives me an error saying expression must have a class type. I have looked at this error and it says it was a pointer issue. My question is why is it only a problem for an array but not for vector??
According to the cppreference, .begin() of an array also gives the initial iterator.
Is there a way to work around this for defining Argmin() over an array?
Any suggestions will be highly appreciated.
Thanks in advance
It seems like you're confusing C++'s std::array with C-style arrays (which is what you're using in the code you posted):
float rev_tone_s[256][3];
This is a C-style array, not a std::array. C-style arrays are basically raw pointers to objects of the underlying type and a pointer does not have the begin method. std::array on the other hand is an STL container which has the begin method.
This means you could just change the type of your rev_tone_s variable if you want to have stuff like STL-iterators:
std::array<std::array<float, 256>, 3> rev_tone_s;
My question is why is it only a problem for an array but not for vector?
vector is an object, so it has member functions like size() and begin() and end() for iterators. While array is just a raw type, just like and int or a float and not an object, so you don't have any member functions for it.
According to the cppreference, .begin() of an array also gives the initial iterator
That is correct, but that array is std::array which is a wrapper over raw arrays. It doesn't allocate any memory at runtime so you can and should use that. Advantage of using the std::array over raw array is that
You get member functions like size() and iterators.
It won't decay to a pointer whenever you pass it as an argument to a function.
Here's how you declare a 2D std::array:
std::array<std::array<float, 256>, 3> arr ;
Note that you need to #include <array> for this to work.
The problem is that you are trying to invoke begin() on a pointer
Here is an example of using distance with pointer:
#include <iostream>
#include <algorithm>
const int arr_size = 100;
float myarray[arr_size];
int main()
{
for(int i = 0; i < arr_size; ++i) {
myarray[i] = static_cast<float>(100 - i);
}
std::cout << std::distance(myarray, std::min_element(myarray, myarray + arr_size)) << '\n';
return 0;
}

Can we use conventional pointer arithmetic with std::array?

I want to work out how to use old style pointer arithmetic on pointers to elements of the std::array class. The following code (unsurprisingly perhaps) does not compile:
int main(int argc, char *argv[])
{
double* data1 = new double[(int)std::pow(2,20)];
std::cout << *data1 << " " << *(data1 +1) << std::endl;
delete data1;
data1 = NULL;
double* data2 = new std::array<double, (int)std::pow(2,20)>;
std::cout << *data2 << " " << *(data2 +1) << std::endl;
delete data2;
data2 = NULL;
return 0;
}
As an exercise, I want to use all the conventional pointer arithmetic, but instead of pointing at an old style double array, I want it to point to the elements of a std::array. My thinking with this line:
double* data2 = new std::array<double, (int)std::pow(2,20)>;
is to instruct the compiler that data2 is a pointer to the first element of the heap allocated std::array<double,(int)std::pow(2,20)>.
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
This raises a couple of questions:
What is the actual meaning of the statement type* name = new othertype[size];?
How can I achieve what I want using std::array?
Finally, how can I achieve the same using std::unqiue_ptr and std::make_unique?
I have been taught that the double* name = new double[size]; means EXACTLY the following: «Stack allocate memory for a pointer to ONE double and name the pointer name, then heap allocate an array of doubles of size size, then set the pointer to point to the first element of the array.» Since the above code does not compile, I must have been taught something incorrect since the same syntax doesnt work for std::arrays.
You are correct about that statement, but keep in mind that the way this works is that new[] is a different operator from new. When you dynamically allocate an std::array, you're calling the single-object new, and the returned pointer points to the std::array object itself.
You can do pointer arithmetic on the contents of an std::array. For example, data2.data() + 1 is a pointer to data2[1]. Note that you have to call .data() to get a pointer to the underlying array.
Anyway, don't dynamically allocate std::array objects. Avoid dynamic allocation if possible, but if you need it, then use std::vector.
Can we use conventional pointer arithmetic with std::array?
Yes, sure you can - but not on the array itself, which is an object. Rather, you use the address of the data within the array, which you get with the std::array's data() method, like so:
std::array<double, 2> data2 { 12.3, 45.6 };
double* raw_data2 = data2.data(); // or &(*data2.begin());
std::cout << *raw_data2 << " " << *(raw_data2 + 1) << std::endl;
and this compiles and runs fine. But you probably don't really need to use pointer arithmetic and could just write your code different, utilizing the nicer abstraction of an std::array.
PS - Avoid using explicit memory allocation with new and delete(see the C++ Core Guidelines item about this issue). In your case you don't need heap allocation at all - just like you don't need it with the regular array.
You can have access to the "raw pointer" view of std::array using the data() member function. However, the point of std::array is that you don't have to do this:
int main(int argc, char *argv[])
{
std::array<double, 2> myArray;
double* data = myArray.data();
// Note that the builtin a[b] operator is exactly the same as
// doing *(a+b).
// But you can just use the overloaded operator[] of std::array.
// All of these thus print the same thing:
std::cout << *(data) << " " << *(data+1) << std::endl;
std::cout << data[0] << " " << data[1] << std::endl;
std::cout << myArray[0] << " " << myArray[1] << std::endl;
return 0;
}
The meaning of a generalized:
type* name = new othertype[size];
Ends up being "I need a variable name that's a pointer to type and initialize that with a contiguous allocation of size instances of othertype using new[]". Note that this involves casting and might not even work as othertype and type might not support that operation. A std::array of double is not equivalent to a pointer to double. It's a pointer to a std::array, period, but if you want to pretend that's a double and you don't mind if your program crashes due to undefined behaviour you can proceed. Your compiler should warn you here, and if it doesn't your warnings aren't strict enough.
Standard Library containers are all about iterators, not pointers, and especially not pointer arithmetic. Iterators are far more flexible and capable than pointers, they can handle exotic data structures like linked lists, trees and more without imposing a lot of overhead on the caller.
Some containers like std::vector and std::array support "random access iterators" which are a form of direct pointer-like access to their contents: a[1] and so on. Read the documentation of any given container carefully as some permit this, and many don't.
Remember that "variable" and "allocated on stack" are not necessarily the same thing. An optimizing compiler can and will put that pointer wherever it wants, including registers instead of memory, or nowhere at all if it thinks it can get away with it without breaking the expressed behaviour of your code.
If you want std::array, which you really do as Standard Library containers are almost always better than C-style arrays:
std::array<double, 2> data2;
If you need to share this structure you'll need to consider if the expense of using std::unique_ptr is worth it. The memory footprint of this thing will be tiny and copying it will be trivial, so it's pointless to engage a relatively expensive memory management function.
If you're passing around a larger structure, consider using a reference instead and locate the structure in the most central data structure you have so it doesn't need to be copied by design.
Sure, these are all legal:
template<class T, std::size_t N>
T* alloc_array_as_ptr() {
auto* arr = new std::array<T,N>;
if (!arr) return nullptr;
return arr->data();
}
template<class T, std::size_t N>
T* placement_array_as_ptr( void* ptr ) {
auto* arr = ::new(ptr) std::array<T,N>;
return arr->data();
}
template<std::size_t N, class T>
std::array<T, N>* ptr_as_array( T* in ) {
if (!in) return nullptr;
return reinterpret_cast<std::array<T,N>*>(in); // legal if created with either above 2 functions!
}
// does not delete!
template<std::size_t N, class T>
void destroy_array_as_ptr( T* t ) {
if (!t) return;
ptr_as_array<N>(t)->~std::array<T,N>();
}
// deletes
template<std::size_t N, class T>
void delete_array_as_ptr(T* t) {
delete ptr_as_array<N>(t);
}
the above is, shockingly, actually legal if used perfectly. The pointer-to-first-element-of-array is pointer interconvertable with the entire std::array.
You do have to keep track of the array size yourself.
I wouldn't advise doing this.
std::array is a STL container after all!
auto storage = std::array<double, 1 << 20>{};
auto data = storage.begin();
std::cout << *data << " " << *(data + 1) << std::endl;

How to solve the error "expression must be a modifiable lvalue" in c++?

const int ADJ_MATRIX[VERTEX_NUM][VERTEX_NUM]={
{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}
};
typedef struct {
int vertex;
int matrix[VERTEX_NUM][VERTEX_NUM];
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX;
}
The error occurs in this sentence:
graph->matrix = ADJ_MATRIX;
I am new to c++. please tell me why this problem occur and how to solve it?
I want to assign ADJ_MATRIX to the matrix in struct.
As was said, you can't assign arrays in C++. This is due to the compiler being a meanie, because the compiler can. It just won't let you do it...
... unless you trick it ;)
template <typename T, int N>
struct square_matrix {
T data[N][N];
};
square_matrix<int, 10> a;
square_matrix<int, 10> b;
a = b; // fine, and actually assigns the .data arrays
a.data = b.data; // not allowed, compiler won't let you assign arrays
The catch? Now the code needs some little things:
const square_matrix<int, VERTEX_NUM> ADJ_MATRIX={{
// blah blah
}}; // extra set of braces
typedef struct {
int vertex;
square_matrix<int, VERTEX_NUM> matrix;
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX; // no change
}
And to access the cells, now we need to use graph->matrix.data[1][2]. This can be mitigated by overloading operator[] or operator() for square_matrix. However, this is now getting terribly close to the new std::array class, or the Boost equivalent boost::array, so it might be wise to consider those instead.
Unfortunately (or maybe fortunately, who knows...) you can't just assign one array to another in C++.
If you want to copy an array, you will need to either copy each of it's elements into a new array one by one, or use the memcpy() function:
for( int i = 0; i < VERTEX_NUM; i++ )
for( int j = 0; j < VERTEX_NUM; j++ )
graph->matrix[i][j] = ADJ_MATRIX[i][j];
or
memcpy( graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int) );
Arrays are not assignable. You can use memcpy:
memcpy(graph->matrix, ADJ_MATRIX, sizeof(graph->matrix));
You cannot assign an array to another array. You will need to copy the elements from the source to the destination index by index, or use memcpy to copy the data. Array assignment like this is not allowed
You are trying to assign your variable address of a constant data,
try using
memcpy(graph->matrix,ADJ_MATRIX,sizeof(ADJ_MATRIX));//using sizeof(graph->matrix) is safer.
You can't use an array in assignments. You may use cycles or memcpy instead
memcpy(graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int));
or
for(int i = 0; i < VERTEX_NUM; ++i){
for(int j = 0; j < VERTEX_NUM; ++j){
graph->matrix[i][j] = ADJ_MATRIX[i][j];
}
}
The error is thrown, because int matrix[VERTEX_NUM][VERTEX_NUM] in a structure definition means that each structure will have a 2D array of integers of the predefined size and matrix is going to be pointing to its first element. The thing is that matrix cannot be assigned to an arbitrary address, because it's a const pointer i.e. its value (the address it's pointing to) cannot change.
You have 2 options here: you can either use memcpy or some stl algorithms to copy the ADJ_MATRIX into matrix directly or you can declare matrix as a pointer and do the assignment that is currently produces an error.
The latter can be done in the following way:
typedef struct {
int vertex;
const int (*matrix)[VERTEX_NUM];
int vNum;
int eNum;
}Graph;
Thus you can do graph->matrix = ADJ_MATRIX assignment, but you won't be able to modify the individual items in matrix due to constness. This means, graph->matrix[0][1] = 3; is not allowed, while you can read the elements freely.