I'm trying to make an empty array in Chapel. An array of one element can be made like this:
var a: [1..1] int = (1);
But when I try
var b: [1..0] int = ();
I get
syntax error: near ')'
Is there an empty array literal in Chapel? I haven't been able to find an example.
EDIT
The reason I am trying to get an empty array is that I would like to implement get this function working for empty arrays:
proc sum_of_even_squares(a) {
// Does this work for empty arrays? Probably not.
return + reduce ([x in a] if x % 2 == 0 then x*x else 0);
}
assert(sum_of_even_squares([7]) == 0);
assert(sum_of_even_squares([7, 3]) == 0);
assert(sum_of_even_squares([7, 3, -8]) == 64);
assert(sum_of_even_squares([7, 3, -8, 4]) == 80);
But I am unable to form an empty array literal.
Generally, in Chapel, to declare an empty thing, you specify its type but no initialization, such as
var i:int;
But to declare an integer initialized with a value, you'd probably leave off the type:
var j = 2;
In this case, simply omitting the initializer makes it work.
var b: [1..0] int;
Relatedly, (1) is not declaring an array literal but rather a tuple literal. The syntax [1] would declare an array literal. At present, zero-length tuples are not supported in the compiler implementation. It might be easier to get zero-length array literals to work, but it doesn't seem to work right now either (in 1.15).
And how would a zero-length array literal know the type of the elements? For this reason I don't think it could help in your specific case.
Related
Trying to change the value of a certain float which is used to define the RGBA of an element. The problem is when I try to change the value of the float an error occurs. Here's an example:
float ColorForScrollbar[4] = {1,0,0,.8};
// Set the value for ColorForScrollbar
ColorForScrollbar[4] = {0,1,0,.8};
// "Error: Expected an expression"
ColorForScrollbar = {0,1,0,.8};
// "Error: Expression must be a modifiable value"
float ColorForScrollbar[4] = {1,0,0,.8};
This is valid. The {1,0,0,.8} is an initializer. It is not, however, an expression. It can only be used after the = in an object declaration.
ColorForScrollbar[4] = {0,1,0,.8};
If this were legal, then it would (attempt to) change the value of ColorForScrollbar[4], not of the entire array. Since the only elements that exist have indices 0, 1, 2, and 3, this would have undefined behavior. But again, {0,1,0,.8} is not an expression, so it can't be used on the RHS of an assignment.
This is closer, but it has the same problem as before. Furthermore, there is no assignment operator for array types.
You can change one element at a time:
ColorForScrollbar[0] = 0;
ColorForScrollbar[1] = 1;
ColorForScrollbar[2] = 0;
ColorForScrollbar[3] = 0.8;
Or, if you want to use the initializer syntax, you can use a temporary object:
#include <cstring>
const float new_value[4] = { 0, 1, 0, 0.8 };
std::memcpy((void*)ColorForScrollbar, (void*)new_value), sizeof ColorForScrollbar);
However, this is all rather low-level. You're probably better off using one of the C++ container classes from the standard library. Which one is best (std::vector, std::array) probably depends on just what you're doing.
An array is really just an address for a contiguous, fixed, area of memory. You can't change it any more than you can change your own street address (unless you move, of course).
What you can change, though, are the contents of an array:
ColorForScrollbar[0]=0;
ColorForScrollbar[1]=1;
ColorForScrollbar[2]=0;
ColorForScrollbar[3]=.8;
You don't have to change every value in the array, just what you need to change.
You can also do an explicit copy:
float NewColorForScrollBar[4] = {0,1,0,.8};
for (i=0; i<4; ++i)
ColorForScrollbar[i]=NewColorForScrollbar[i];
I am looking at docs and can't understand hot can I create array of Tuples. It's compile fine:
auto myDataTuple = tuple(url, path);
but this code produce error:
auto myDataTuples [] ~= myDataTuple;
Error: no identifier for declarator myDataTuples[].
It's can't understand type for myDataTuples or what?
You can't append to a declaration since it doesn't exist yet.
The type tuple(x, y) returns is Tuple!(typeof(x), typeof(y)). You can make an array of them. So if url and path are both strings, try:
Tuple!(string, string)[] myDataTuple; // the [] makes an array
myDataTuple ~= tuple(url, path);
PS: it is my opinion that structs are better than tuples basically all the time. (a Tuple is just a generated struct anyway). You can probably also do struct MyData { string url; string path; } and use MyData everywhere too. It is easier to realize what it is later.
To define an array using a set of existing variables and values you can list them inside braces [] and declare the array just like an ordinary variable:
string url, path;
auto myDataTuple = tuple(url, path);
auto myDataTuples = [myDataTuple];
// Print out the type for better understanding: Tuple!(string, string)[]
writeln(typeof(myDataTuples).stringof);
This creates a new dynamic array with one element that can be append to.
Appending to an existing array works like this:
// Append an item (variable and literal)
myDataTuples ~= anotherTuple;
myDataTuples ~= tuple(url2, path2);
// Append an array (variable and literal)
myDataTuples ~= anotherArray;
myDataTuples ~= [tuple(url3, path3), tuple(url4, path4)];
I have the following piece of code which after running throws error :
class arr2{
int count;
public:
int elem[5];
arr2()
{
count=-1;
elem[5]=(0,0,0,0,0); //{} throws error i dont know why
}
};
int main()
{
arr2 obj;
vector<int> vec;
vec.assign(10,42);
vector<int> ::iterator itr=vec.begin();
for(;itr!=vec.end();++itr){
cout<<*itr<<endl;
}
return 0;
}
ERROR stack around the variable 'obj' was corrupted.
If i remove arr2 obj; then it works fine.
Is there anything wrong with the class itself or the statement in ctor elem[5]=(0,0,0,0,0);
I tried to define an array in main with {} and it works fine. I dont know why it fails when inside class.
int arr4[4]={1,2,3,4}; //OK
int elem[5]; // Represents that the array is of size 5
Since array index starts with 0, the available array indices are:
elem[0]
elem[1]
elem[2]
elem[3]
elem[4]
(total five elements)
elem[5] is out of bounds.
You need to consider that there are two distinct constructs at work here.
Initialisation
// initialiser
// |
// name ("elem") |
// | |
// ▼▼▼▼ ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
int elem[5] = {0, 0, 0, 0, 0};
// ▲▲▲ ▲▲▲
// \ /
// \ /
// \ /
// type (int[5])
Assignment
// new element value
// |
// name ("elem") |
// | |
// ▼▼▼▼ ▼▼▼▼▼
elem[n] = 12345;
// ▲▲▲ ▲
// | |
// | assignment operator
// |
// index (n)
Your problem has nothing to do with whether you write your code in main or in a class definition; the problem is that you are trying to write an assignment as if it were an initialisation.
The initialiser {0, 0, 0, 0, 0} simply cannot be used in an assignment
When you write elem[5] instead of int elem[5], you're naming the 6th element of elem, not declaring a new array of size 5 called elem.
The error goes away when you use (0, 0, 0, 0, 0) instead, because this is an expression that evaluates to 0, and you can assign 0 to an element of an int array.
Unfortunately, you're doing so to an element that does not exist, because elem[5] is out of bounds. It's a hypothetical sixth element in a five-element array.
The inability to use initialiser syntax to assign to all of an array's elements in one fell swoop is a limitation of C and C++.
To assign to the array at an arbitrary place, you'd have to assign them one by one in a loop, or use a fill function:
std::fill(std::begin(elem), std::end(elem), 0);
…which is much better anyway.
Fortunately, you've committed another crime that's actually quite convenient: you actually do want to initialise, even though at the moment you're instead assigning inside the constructor body. To initialise class members, you must use the constructor's member-initialiser list and, as it happens, the constructor's member-initialiser list enables us to use initialiser syntax:
arr2()
: elem{0, 0, 0, 0, 0}
{}
…or, more simply:
arr2()
: elem{}
{}
The assignment
elem[5]=(0,0,0,0,0);
write a single zero (read about the comma operator) at the sixth place in the array (remember that array indexes are zero-based), which is one beyond the end of the array. Writing beyond the bounds of an array leads to undefined behavior.
There are a few ways to initialize the array, the simplest being a constructor initializer list:
class arr2
{
int elem[5];
public:
arr2()
: elem{}
{}
};
The above will value-initialize the array, which means that each element in the array also will be value-initialized, and for an int value-initialization will set it to 0.
To expand on the error you get, just about all systems and compilers today store local variables on the stack, that includes the variable obj in your main function. Placing an object on the stack also places its member variables on the stack. If you write out of bounds of the array, then you also write on stack-memory you do not own the right to, and therefore corrupt the stack.
This does not do what you expect:
elem[5]=(0,0,0,0,0);
You assign the element at index 5 (which is out of bounds) the value 0. You do not assign an initializer list, but rather a series of zeroes with the comma operator in between (which returns the second value of each call), which in turn returns the rightmost zero.
elem[5]=(0,0,0,0,0); //{} throws error i dont know why
using {} throws error because, {} have to be used only for initialization of array, not for assignment.
Also above statement is not assigning all your array elements to zero, instead it tries to assign one zero to elem[5], which is actually out of boundary of your array.
your array starts at elem[0] and ends at elem[4].
elem[5] is actually refers to the address of vector defined below.
vector vec;
As you are corrupting this memory. You got exception.
I'm using the LLVM 3.3 C++-API. My code creates arrays using ConstantArray::get, and multidimensional arrays with recursive code (the innermost rank is first converted to a vector of Constant*s, as above, then that is used to initialize the next-innermost rank, and so on).
I tried to optimize this by saying that if an array's element type satisfies the ConstantDataArray::isElementTypeCompatible predicate, then it should be initialized using ConstantDataArray::get.
Here's a more concrete example to show what I mean:
Say the array I want to create would be declared like this in C++:
int x[2][3] = {{1,2,3},{4,5,6}};
The innermost rank (type int[3]) is a simple array type, so two CDAs are created.
The next rank is an array of two int[3]s. It is not a simple type, so a regular ConstantArray is created. The argument is an ArrayRef<Constant*> containing the two CDAs.
At step 3, ConstantArray complains because the initializer does not have exactly the right type. Here's the message:
.../llvm-3.3.src/lib/IR/Constants.cpp:754:
static llvm::Constant* llvm::ConstantArray::get(llvm::ArrayType*,
llvm::ArrayRef<llvm::Constant*>):
Assertion `V[i]->getType() == Ty->getElementType()
&& "Wrong type in array element initializer"' failed.
I though ConstantDataArray was a substitute for ConstantArray when the element type is simple enough, but maybe I have it wrong. What's the correct way to understand it?
Update
This looks like a bug in my code (outside of LLVM). ConstantDataArray does appear to be a transparent substitute for ConstantArray.
Here's the code I put together to demonstrate the problem. It actually runs through without any complaints from LLVM:
// int[2][3] = {{1,2,3},{4,5,6}};
IntegerType* i64 = IntegerType::get(mod->getContext(), 64);
Constant* one = ConstantInt::get(i64, 1);
Constant* two = ConstantInt::get(i64, 2);
Constant* three = ConstantInt::get(i64, 3);
Constant* four = ConstantInt::get(i64, 4);
Constant* five = ConstantInt::get(i64, 5);
Constant* six = ConstantInt::get(i64, 6);
ArrayType* int_3 = ArrayType::get(i64, 3);
ArrayType* int_2_3 = ArrayType::get(int_3, 2);
// Constant* array123 = ConstantArray::get(int_3, std::vector<Constant*>{one,two,three});
Constant* array123 = ConstantDataArray::get(mod->getContext(), std::vector<uint64_t>{1,2,3});
// Constant* array456 = ConstantArray::get(int_3, std::vector<Constant*>{four,five,six});
Constant* array456 = ConstantDataArray::get(mod->getContext(), std::vector<uint64_t>{4,5,6});
Constant* array = ConstantArray::get(int_2_3, std::vector<Constant*>{array123, array456});
In case anyone is interested, the assertion stems from my reversing the array extents. int[2][3] is an array of two arrays of three. I'm overloading operator[] to build an array type as i64[2][3], where i64 is an object that holds an IntegerType* and overloads operator[]. The problem is that this builds an array of three arrays of two.
Below is the code
void printLoop(type?? p){
for(int i = 0; i<2;i++)
{
for(int e = 0;e<3;e++)
{
cout<<p[i][e]<<" ";
}
cout<<"\n";
}
}
void array()
{
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a;
printLoop(p);
}
Basic idea is that I want to print out the array using a for loop in the printLoop func. However, I need to know the type of that pointer which has the address of the 2D array. What's the pointer's type? Is it int (*)[]? I'm confused.
Also what does "(*p)" mean(from int (*p)[3]) ? Thanks a lot!
what does "(*p)" mean(from int (*p)[3]) ?
p is a pointer to an array of size 3 of objects of type int.
You have multiple possibilites for your printLoop function (though with the general C-restriction that you can leave at most one -- the outermost declarator empty):
You can specify the dimensions explicitly:
void printLoop(int p[ 2 ][ 3 ]);
The only advantage with this method is that the implementation can consider that the array being passed is of the desired size (i.e. 2x3 matrix of ints) as a pre-condition.
You can leave out the [ 2 ] part entirely:
void printLoop(int p[][ 3 ]);
or,
void printLoop(int (*p)[ 3 ]);
You can use a pointer to a pointer of int
You will also need to pass the dimensions (if you skip one that is) along to make sure that you don't access out-of-bounds memory. So, your function signature should go like this:
void printLoop(int (*p)[ 3 ], int dim);
For the printLoop function, int p[2][3] as an argument should just work.
int (*p)[3] = a;
p is a pointer to an array of 3 ints, initialized to point to a.
First of all, your code is not very modern C++. It's basically "c with iostreams".
Second of all, printLoop(int p[2][3]) is the signature you're looking for even though again, it's not the best way of doing things at all.
Third of all, int (*p)[3] is analyzed as follows: Start at the name which is p and take a look around (first to the right and then to the left yet here it doesn't matter) until you "hit" braces. There's only a star at it, so you can say that p is a pointer. Now you recursively do the same analysis again, you see [3], which means that p is a pointer to an array that has 3 ints.
Now I'd like to mention the following:
Use std::array for staticly-sized arrays.
Use std::vector for dynamicaly-sized arrays.
Oh, also, I myself wouldn't use a 2D array, they are clunky and just a syntactic sugar (around the basic "array" notion which is a syntactic sugar as well).
So perhaps, something like this, brain compiled, hopefully correct, C++11 abusing:
std::array<int, 3 * 2> p = {{1, 2, 3, 4, 5, 6}};
std::for_each(std::begin(p), std::end(p), [](int elem){ std::cout<<elem; });
Nice and dandy. You could also have lambda check for some "2d array" sizes and insert newlines if you so desire.