Array Creation Problems in C++ - c++

I'm a novice programmer trying to get a head start on some classes before the summer semester starts, and I've run into this problem while trying to create a Quick Union algorithm in C++.
I've been trying to figure out why my program creates two identical arrays, despite having two separate for loops designed to create two different arrays. Whenever my program runs to completion and prints id[] and sz[], it always outputs 1 as the element at every index in both arrays.
class quickUnionUF{
private:
int id[];
int sz[];
int root(int);
public:
quickUnionUF(int, int);
bool connected(int, int);
void unionPoint(int, int);
void print();
};
quickUnionUF::quickUnionUF(int n, int b){
id[n];
sz[b];
for(int i=0;i<n;i++){
id[i] = i;
}
for(int j=0;j<b;j++){
sz[j] = 1;
}
}
For example, if I create quickUnionUF(5, 5);
id[] should now contains elements:
0, 1, 2, 3, 4
And sz[] contains elements:
1, 1, 1, 1, 1
However, the program creates an array sz[] AND array id[] with elements:
1, 1, 1, 1, 1
Any thoughts as to why this is happening?

Standard C++ does not have sizeless array members.
Use std::vector<int> as dynamically sized arrays in C++.
#include <vector>
class quickUnionUF{
private:
std::vector<int> id;
std::vector<int> sz;
int root(int);
public:
quickUnionUF(int, int);
bool connected(int, int);
void unionPoint(int, int);
void print();
};
quickUnionUF::quickUnionUF(int n, int b)
: id(n)
, sz(b)
{
for(int i=0;i<n;i++){
id[i] = i;
}
for(int j=0;j<b;j++){
sz[j] = 1;
}
}

Your code hints at a two very important mistakes:
C++ does not work like Java. int id[] is not an reference to an array of arbitrary size on the garbage collected heap. It is instead a member array of undefined size used to implement dynamic arrays (and similar features) in C99. You should never use this syntax unless you know exactly what you are doing, because it is almost guaranteed to be wrong otherwise.
id[n] does not allocate an array at all. Instead it just indexes id and discards the result.
Listen to your compiler!
First, your code should not compile due to the fact, that only the last member of a struct may be a flexible array type. In fact clang howls:
main.cpp:53:9: error: field has incomplete type 'int []'
int id[];
MSVC howls:
1>main.cpp(54): error C2229: class 'quickUnionUF' has an illegal zero-sized array
And g++ only warns (well, g++ is strange in what it accepts sometimes):
main.cpp:53:12: warning: ISO C++ forbids zero-size array ‘id’ [-Werror=pedantic]
int id[];
Note: g++ is wrong in compiling this, even if one allows flexible array members. This is defined in C99 6.7.2.1§16 and C11 6.7.2.1§18 both of which begin with (emphasis is mine):
As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member. [...]
What is happening?
Well, assuming you got your code to compile anyway, it basically means the following:
Create an object with the alignment of integers, but NO elements at all. Take a peek at the following test program:
quickUnionUF q;
::std::cout << sizeof(quickUnionUF) << "\n";
::std::cout << &q << "\n" << &q.id[0] << "\n" << &q.sz[0] << "\n";
The only compiler that managed to compile this at all (gcc 4.9.0) gave the following result:
0
0x7fff1bf6274c
0x7fff1bf6274c
0x7fff1bf6274c
So, this is a zero byte object (yes, this is illegal C++, since every C++ object has a size > 0) and the first element of each array is at the same position (OUTSIDE YOUR OBJECT!). Remember, you declared id and sz to have zero elements!
Therefore, you are writing to the same arbitrary position. You can consider this the extreme case of a buffer overflow: By writing 5 integers to a zero size buffer, you are overflowing from the first zero size buffer through the second zero size buffer into memory totally not under your control.
This also explains your observed result: The second loop simply overwrites what the first did (and it still does it by corrupting your stack).
How do I fix this?
Just use a vector. You can tell it how big you want it and you can ask it to tell you when you are indexing to some position that is not yours.

Related

Passing a pointer to an int array to a member function, error: invalid types 'int[int]' for array subscript

Ok, I'm fairly new to programming, and c++ so please take it easy on me. I am trying to write a program that takes in the dimensions of a metal plate for a 2-D finite element method analysis (thickness neglected). So, I created a class for my part (the plate), the elements for the mesh, and the nodes for the elements. The mesh will consist of square elements and will be applied over the front face of the plate. Right now, I'm working on getting the mesh sorted out before I move on to the element and node classes.
I'm using (or wanting to use) dynamic allocation to create a 2-D array (my mesh) containing the elements of the mesh. I'm trying to write a function, "meshingPart", to create the 2-D array with the number of rows being the height of the plate, and the columns being the length of the plate.
When I run the program, I get these errors and I'm not sure how to fix them:
In member function 'void PartClass::meshingPart(int&, int, int)':
error: invalid types 'int[int]' for array subscript
At global scope:
error: expected constructor, destructor, or type conversion before '(' token
Also, when I use my printPart() function, will it print the pointer's address, or the values of the array? I'm not completely sure about this, I'm also new to pointers.
Any help would be much appreciated! Thanks in advance.
class PartClass
{
private:
const int HEIGHT; // mm
const int LENGTH; // mm
const int WIDTH; // mm
const int SEED; // mm
const int MESHROW;
const int MESHCOL;
int *partMesh; // Mesh array - an int pointer
// Creates the mesh for the part by generating elements to fill the width and length
// of the part. The elements are stored in a 2-D array.
void meshingPart(const int &partMesh, int inRow, int inCol);
public:
// Constructs a part with the given parameters, seeds the part for the mesh,
// then creates the mesh by generating square elements with length = height = SEED.
PartClass(int inHeight, int inLength, int inWidth, int inSeed);
void printPart()
{
cout << "Part mesh:" << *partMesh << endl;
}
};
class ElementClass
{
private:
int elemID;
static int numElems;
// Shape functions:
int N1;
int N2;
int N3;
int N4;
public:
// Default constructor
ElementClass()
{
elemID = numElems;
numElems++;
};
};
PartClass :: PartClass(inHeight, inLength, inWidth, inSeed)
{
HEIGHT = inHeight;
LENGTH = inLength;
WIDTH = inWidth;
SEED = inSeed;
MESHROW = HEIGHT/SEED;
MESHCOL = LENGTH/SEED;
// Dynamically declares an array, gets memory, assigns address to partMesh.
partMesh = new int[MESHROW][MESHCOL];
meshingPart(&partMesh, MESHROW, MESHCOL);
}
void PartClass :: meshingPart(int &partMesh, int inRow, int inCol)
{
for( int i; i < inRow; i++)
{
for( int j; j < inCol; j++)
{
partMesh[i][j] = ElementClass();
}
}
}
There are multiple problems with the shown code, not a single problem. All of the problems must be fixed in order to resolve all compilation errors.
void PartClass :: meshingPart(int &partMesh, int inRow, int inCol)
The first parameter to this class method is declared as a reference to a single, lonely int. It is not an array, hence the code in this class method that treats it as an array will make your C++ compiler very, very sad.
int *partMesh; //
partMesh = new int[MESHROW][MESHCOL];
partMesh is declared as a pointer to an int. The new expression produces, effectively, a pointer to an array of MESHCOL ints. In C++ you cannot convert a pointer to an array into a different kind of a pointer.
Furthermore, nothing shown here requires the use of new in the first place. partMesh could simply be a std::vector<vector<int>>, and the new replaced by a strategic resize(). As an extra bonus your C++ program will automatically delete all this memory when it is no longer needed, not leak it, and also implement correct copy/move semantics where needed!
meshingPart(&partMesh, MESHROW, MESHCOL);
As we've concluded, the first parameter to the function is a reference to an array. Passing to it an address of a pointer to int will also not work.
Furthermore, since partMesh is a member of the same class, having one function in the class pass, in some form, a member of the same class to another class method accomplishes absolutely useful, whatsoever. Since it's a member of the same class it doesn't need passing, the class method can access it directly. This is what, after all, classes are all about.
In conclusion:
There are several problems regarding the C++ type system that are causing these compilation errors.
It is not necessary to even use new here, to initialize the pointer, and either its type needs to be adjusted to reflect that it's a pointer to a 2D array, or the new statement itself needs to be adjusted to allocate a one-dimensional array, since that's the only thing C++ allows you to convert to a plain pointer. And even that is overnegineered, since a std::vector will take care of all these pesky details by itself.
It is not necessary to even pass the member of the same class to the same class's method, as a parameter, just have the class method access it directly.
It's apparent that the likely process that produced the shown code was to write it in its entirety, and only try to compile after the whole thing was written. An avalanche of compilation errors is almost guaranteed any time this approach is used. It is far more productive to write a large program by writing only a few lines at a time, testing them, make sure they work correctly, and only then write a few more. This way, the number of errors that need to be fixed will remain quite small, and manageable.

C++ error in malloc

I am new to C/C++ and trying to test my understanding of pointers. For this I created the following simple program to create an integer array to store 10 numbers and print it out.
#include<iostream>
#include <cstdlib>
// #include <cstdint>
int main(){
int numberOfItems = 10;
int *array;
// int *array = malloc((int*)numberOfItems*sizeof(int));
array = malloc((int*)numberOfItems*sizeof(int));
for(int i=0;i<numberOfItems;i++){
*array = i;
array++;
i++;
}
std::cout<<"The size of the array is : "<<sizeof(array)<<std::endl;
for(int i=0;i<numberOfItems;i++){
std::cout<<*array<<std::endl;
array++;
i++;
}
return 0;
}
I ran the program using the command g++ main.cpp.
But it gives me the following error:
main.cpp:8:47: error: invalid operands of types ‘int*’ and ‘long unsigned int’ to binary ‘operator*’
array = malloc((int*)numberOfItems*sizeof(int));
Tried and Failed
I tried to change the int to uint64_t but still it gave me similar kind of error.
I do not understand what I am doing wrong.
The error is due to the fact that your syntax is incorrect in the following line.
array = malloc((int*)numberOfItems*sizeof(int));
The right syntax would be as follows:
array = (int*) malloc(numberOfItems*sizeof(int));
You need to typecast the return value of malloc as it returns a (void *) pointer. So, you need to specify what type of data you would be pointing when you access the memory.
Let's go through your code step by step:
int *array;
array = malloc((int*)numberOfItems*sizeof(int));
Here you have two problems:
malloc is C, not C++. Yes, malloc is supported in C++, but for backwawrds compatibility with legacy code. Do not use it.
You cast numberOfItems to a pointer, then multiply the pointer with an integer. That's undefined behavior. Your compiler might even do the right thing here, but you cannot know and you cannot trust any result you're getting.
Let's continue:
for(int i=0;i<numberOfItems;i++){
*array = i;
array++;
i++;
}
The for declaration looks fine. You initialize an integer i to 0, and you increment it using the ++ operator as long as it is smaller than numberOfItems, that's good. But:
You increment i again inside your loop. That means you actually increment i by 2, so i goes 0, 2, 4, 6, 8, 10, and your loop is only executed 5 times.
You increment your array pointer. While technically perfectly valid code, this will bite you further down.
So you write the values 0, 2, 4, 6 and 8 into memory at the initial location of your array pointer, and 1*sizeof(int), 2*sizeof(int), 3*sizeof(int), 4*sizeof(int) bytes further down each.
Next problem:
std::cout<<"The size of the array is : "<<sizeof(array)<<std::endl;
This will not print what you meant it to print. array is a pointer type, so sizeof(array) will return the size of a pointer, which is probably either 4 or 8 bytes depending on the bitnes of your application/OS.
And last but not least your last loop:
for(int i=0;i<numberOfItems;i++){
std::cout<<*array<<std::endl;
array++;
i++;
}
You do the same thing with i as in your first loop. This time, this saves your neck, because...
...since you incremented the pointer array already in your first loop, you're now continuing at 5*sizeof(int) bytes further down in the memory. You're therefore not printing the values you set in the first loop (which was probably your intention), but uninitialized values that reside in the second half of the memory originally allocated at array.

passing variable sized array into a function [duplicate]

There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.
How to pass multidimensional variable length array to a function in C99/C11?
For example:
void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}
void bar(int n)
{
int arr[n][n];
foo(n, arr);
}
Compiler (g++-4.7 -std=gnu++11) says:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first
If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’
Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.
With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:
void foo2(int n, int arr[][10]) // <-- ok
{
}
void bar2()
{
int arr[10][10];
foo2(10, arr);
}
I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.
Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you're actually passing a pointer.
To address a 2D array (a real one, not array of arrays), you'll need to pass 2 chunks of data:
the pointer to where it starts
how wide one row is
And these are two separate values, be it C or C++ or with VLA or without or whatnot.
Some ways to write that:
Simplest, works everywhere but needs more manual work
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA, standard C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
VLA w/ reversed arguments, forward parameter declaration (GNU C extension)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
C++ w/ VLA (GNU C++ extension, terribly ugly)
void foo(int width, int* ptr) {
typedef int arrtype[][width];
arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
arr[x][y]=5;
}
Big remark:
The [x][y] notation with a 2D array works because the array's type contains the width. No VLA = array types must be fixed at compile-time.
Hence: If you can't use VLA, then...
there's no way to handle it in C,
there's no way to handle it without a proxy class w/ overloaded operator overloading in C++.
If you can use VLA (C99 or GNU C++ extensions), then...
you're in the green in C,
you still need a mess in C++, use classes instead.
For C++, boost::multi_array is a solid choice.
A workaround
For 2D arrays, you can make two separate allocations:
a 1D array of pointers to T (A)
a 2D array of T (B)
Then set the pointers in (A) to point into respective rows of (B).
With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.
This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It's also slower than the VLA solution because of the extra layer of indirection.
You may also run into a similar solution with a separate allocation for every B's row. In C this looks like a malloc-in-a-loop, and is analogous of C++'s vector-of-vectors. However this takes away the benefit of having the whole array in one block.
There is no clear cut way for doing this but you can use a workaround to treat a 2 dimensional array as a one dimensional array and then reconvert it to a two dimensional array inside the function.
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}

How to protect an array definition againt incomplete initialization with non-zero values?

I have a global array, which is indexed by the values of an enum, which has an element representing number of values. The array must be initialized by a special value, which unfortunately is not a 0.
enum {
A, B, C, COUNT
};
extern const int arr[COUNT];
In a .cpp file:
const int arr[COUNT] = { -1, -1, -1 };
The enum is occasionally changed: new values added, some get removed. The error in my code, which I just fixed was an insufficient number of initialization values, which caused the rest of the array to be initialized with zeroes. I would like to put a safeguard against this kind of error.
The problem is to either guarantee that the arr is always completely initialized with the special value (the -1 in the example) or to break compilation to get the developers attention, so the array can be updated manually.
The recent C++ standards are not available (old ms compilers and some proprietary junk). Templates can be used, to an extent. STL and Boost are strongly prohibited (don't ask), but I wont mind to copy or to reimplement the needed parts.
If it turns out to be impossible, I will have to consider changing the special value to be 0, but I would like to avoid that: the special value (the -1) might be a bit too special and encoded implicitly in the rest of the code.
I would like to avoid DSL and code generation: the primary build system is jam on ms windows and it is major PITA to get anything generated there.
The best solution I can come up with is to replace arr[COUNT] with arr[], and then write a template to assert that sizeof(arr) / sizeof(int) == COUNT. This won't ensure that it's initalized to -1, but it will ensure that you've explicitly initialized the array with the correct number of elements.
C++11's static_assert would be even better, or Boost's macro version, but if you don't have either available, you'll have to come up with something on your own.
This is easy.
enum {
A, B, C, COUNT
};
extern const int (&arr)[COUNT];
const int (&arr)[COUNT] = (int[]){ -1, -1, -1};
int main() {
arr[C];
}
At first glance this appears to produce overhead, but when you examine it closely, it simply produces two names for the same variable as far as the compiler cares. So no overhead.
Here it is working: http://ideone.com/Zg32zH, and here's what happens in the error case: http://ideone.com/yq5zt3
prog.cpp:6:27: error: invalid initialization of reference of type ‘const int (&)[3]’ from expression of type ‘const int [2]’
For some compilers you may need to name the temporary
const int arr_init[] = { -1, -1, -1};
const int (&arr)[COUNT] = arr_init;
update
I've been informed the first =(int[]){-1,-1,-1} version is a compiler extension, and so the second =arr_init; version is to be preferred.
Answering my own question: while it seems to be impossible to provide the array with the right amount of initializers directly, it is really easy to just test the list of initializers for the right amount:
#define INITIALIZERS -1, -1, -1,
struct check {
check() {
const char arr[] = {INITIALIZERS};
typedef char t[sizeof(arr) == COUNT ? 1: -1];
}
};
const int arr[COUNT] = { INITIALIZERS };
Thanks #dauphic for the idea to use a variable array to count the values.
The Boost.Preprocessor library might provide something useful, but I doubt whether you will be allowed to use it and it might turn out to be unwieldy to extract from the Boost sources.
This similar question has an answer that looks helpful:
Trick : filling array values using macros (code generation)
The closest I could get to an initialization rather than a check is to use a const reference to an array, then initialize that array within a global object. It's still runtime initialization, but idk how you're using it so this may be good enough.
#include <cstring>
enum {A, B, C, COUNT};
namespace {
class ArrayHolder {
public:
int array[COUNT]; // internal array
ArrayHolder () {
// initialize to all -1s
memset(this->array, -1, sizeof(this->array));
}
};
const ArrayHolder array_holder; // static global container for the array
}
const int (&arr)[COUNT] = array_holder.array; // reference to array initailized
// by ArrayHolder constructor
You can still use the sizeof on it as you would before:
for (size_t i=0; i < sizeof(arr)/sizeof(arr[0]); ++i) {
// do something with arr[i]
}
Edit
If the runtime initialization can never be relied on you should check your implementation details in the asm because the values of arr even when declared with an initializer may still not be known at until runtime initialization
const int arr[1] = {5};
int main() {
int local_array[arr[0]]; // use arr value as length
return 0;
}
compiling with g++ -pedantic gives the warning:
warning: ISO C++ forbids variable length array ‘local_array’ [-Wvla]
another example where compilation actually fails:
const int arr1[1] = {5};
int arr2[arr1[0]];
error: array bound is not an integer constant before ']' token
As for using an array value as a an argument to a global constructor, both constructor calls here are fine:
// [...ArrayHolder definition here...]
class IntegerWrapper{
public:
int value;
IntegerWrapper(int i) : value(i) {}
};
const int (&arr)[COUNT] = array_holder.array;
const int arr1[1] = {5};
IntegerWrapper iw1(arr1[0]); //using = {5}
IntegerWrapper iw2(arr[0]); //using const reference
Additionally the order of initalization of global variables across different source files is not defined, you can't guarantee the arr = {-1, -1, -1}; won't happen until run time. If the compiler is optimizing out the initialization, then you're relying on implementation, not the standard.
The point I really wanna stress here is: int arr[COUNT] = {-1, -1, -1}; is still runtime initialization unless it can get optimized out. The only way you could rely on it being constant would be to use C++11's constexpr but you don't have that available.

Multiple arrays in a class and XCode

I am trying to use XCode for my project and have this code in my .h:
class FileReader
{
private:
int numberOfNodes;
int startingNode;
int numberOfTerminalNodes;
int terminalNode[];
int numberOfTransitions;
int transitions[];
public:
FileReader();
~FileReader();
};
I get a "Field has incomplete type int[]" error on the terminalNode line... but not on the transitions line. What could be going on? I'm SURE that's the correct syntax?
Strictly speaking the size of an array is part of its type, and an array must have a (greater than zero) size.
There's an extension that allows an array of indeterminate size as the last element of a class. This is used to conveniently access a variable sized array as the last element of a struct.
struct S {
int size;
int data[];
};
S *make_s(int size) {
S *s = (S*)malloc(sizeof(S) + sizeof(int)*size);
s->size = size;
return s;
}
int main() {
S *s = make_s(4);
for (int i=0;i<s->size;++i)
s->data[i] = i;
free(s);
}
This code is unfortunately not valid C++, but it is valid C (C99 or C11). If you've inherited this from some C project, you may be surprised that this works there but not in C++. But the truth of the matter is that you can't have zero-length arrays (which is what the incomplete array int transitions[] is in this context) in C++.
Use a std::vector<int> instead. Or a std::unique_ptr<int[]>.
(Or, if you're really really really fussy about not having two separate memory allocations, you can write your own wrapper class which allocates one single piece of memory and in-place constructs both the preamble and the array. But that's excessive.)
The original C use would have been something like:
FileReader * p = malloc(sizeof(FileReader) + N * sizeof(int));
Then you could have used p->transitions[i], for i in [0, N).
Such a construction obviously doesn't make sense in the object model of C++ (think constructors and exceptions).
You can't put an unbound array length in a header -- there is no way for the compiler to know the class size, thus it can never be instantiated.
Its likely that the lack of error on the transitions line is a result of handling the first error. That is, if you comment out terminalNode, transitions should give the error.
It isn't. If you're inside a struct definition, the compiler needs to know the size of the struct, so it also needs to know the size of all its elements. Because int [] means an array of ints of any length, its size is unknown. Either use a fixed-size array (int field[128];) or a pointer that you'll use to malloc memory (int *field;).