arrays with missing sizes vs pointers - c++

I have generally thought that the following two prototypes were interchangeable:
int main(int argc, char ** argv);
int main(int argc, char * argv[]);
In general I had imagined that char ** argv and char * argv[] were interchangeable. However, I have also come accross some stuff on the internet that claim that you can declare structs like
struct S {
int size;
int ar[];
};
And then simply malloc appropriately so that ar can be as large as you want at runtime.
But this seems rather strange to me. If I had instead declared
struct S {
int size;
int * ar;
};
Can I still do the same thing? I would have imagined this depends on what you make ar point to.
How exactly are int * ar and int ar[] different when used inside a struct? What about with char ** argv and char * argv[] in function prototypes? Do they have different semantics in C as opposed to in C++?

There's a special-case rule for function parameters that look like arrays. Any such parameter is "adjusted" to a pointer to the (possibly qualified) element type.
Because of this rule, these definitions:
int main(int argc, char **argv) { /* ... */ }
and
int main(int argc, char *argv[]) { /* ... */ }
are exactly equivalent. (There's a similar rule for parameters of function type, which are adjusted to function pointers.)
This rule applies only to parameter declarations.
One annoying consequence is that if you declare an array parameter with a size, it's silently ignored:
void func(int array[42]);
really means
void func(int *array);
(There is a usage of the static keyword, added in C99, which I won't go into here.)
struct S {
int size;
int ar[];
};
This is a flexible array member, a feature added in C99. It declares that ar is an array (not, I repeat not, a pointer) of unspecified size. To use it, you have to allocate enough space to hold however many elements you're going to need at run time. This was added to the language as a replacement for the "struct hack", described in question 2.6 of the comp.lang.c FAQ.
Section 6 of the same FAQ is an excellent resource for explaining the often confusing relationship between arrays and pointers.

There is a special rule for using arrays types in function arguments: They become pointer types. However, that rule only holds for function arguments.
This becomes very obvious when you replace the undefined size with, e.g. a size of two:
void f(int x[2]); // equivalent to void f(int* x);
struct A {
int q[2]; // obviously not equivalent to int* q;
};
The structure definition you used
struct S {
int size;
int ar[];
};
is intended to say that an arbitrary amount of ints is supposed to follow the size member - probably exactly size elements. You cannot just leave out the last member, because that could lead to errors w.r.t. alignment and padding (assume for a second that ar was an array of doubles, and you will see the problem).
This syntax is an evolution of an old trick and has been added in C99.

You can use both the first and the second layout for the same purpose, but the layout in memory will not be the same. For the first example, you'd have (assuming a 32 bit architecture):
[size (4 bytes)][ar (size bytes)]
And for the second one:
[size (4 bytes)][pointer to ar (4 bytes)][ar (size bytes)]
So the second solution wastes memory.

char ** and char *[] are indeed the same. In fact, the below will work:
void foo(int a1[]) {
int a2[3];
a2 = 0; // ERROR: Can't assign to an array.
a1 = 0; // OKAY: You can assign to it, because it's actually a pointer!
...
The struct S that you show is using a flexible array member, though. It takes up no space. You can't assign to it. Basically, int [] means different things depending on whether it is a member or a parameter. In the struct where you have the pointer, though, you can basically make that point anywhere.

Related

How to define array size in a struct from an "external" int defined in input

I have a struct with an array in it. The size of this array needs to be 3*input_variable. How can I define a number externally, which is multiplied by an input value, that I can use in a struct to declare the length of an array?
I have tried defining the variable h outside of main as
extern h
then assigning it's value in main from the input variable.
I have also tried to use (in summary)
nt main(int argc, char** argv)
{
int input_variable;
std::cin << input_variable;
int h = input_variable * 3;
void some_function(); // function does some stuff
// with the structs
#ifndef ARRAY_SIZING
#define ARRAY_SIZING h
#endif
return 0;
}
struct _struct_
{
constexpr std::size_t b = ARRAY_SIZING;
double* arr[b];
};
int some_function()
{
// structs are used down here.
return 0;
}
I would love to be able to allocate the size of an array in a struct using an input parameter. Thank you.
Hm. Plain C-arrays in C++. Mostly never needed. OK, you want to interface to a library function.
My guess is that the library does not expect an array, but a pointer. And since your struct contains an array to pointer to doubles, I assume the lib wants to see a double**.
I hardly can imagine that old libraries use references or pointer to arrays, something like:
void function (double* (&array)[10]); // Reference to array
void function (double* (*array)[10]); // Pointer to array
because also here you need an array with a size known at compile time.
I'd rather expect something like
void function (double** array, size_t size); // Pointer to Pointer to double
So, use a std::vector like this:
std::vector<double *> arr(input_variable * 3);
And if you want to hand over the arrays data to the lib functions, then use the vectors data function.
function (arr.data());
You could also create the array with new.
Last hint: Do not use raw pointers.
I hope that I could help a little . . .

Passing struct of array as reference c++

I am new to structure programming, and I find it quite confusing when trying to pass a structure of array in c++. I have a project to do for college, a Star Trek game. This is the sample code:
void main_menu(char,char [][sz2],int&,struct enterpriseSt*,struct klingonSt*[100]);
void combat_menu(char [][sz2],struct enterpriseSt*,int&,struct klingonSt*[100]);
struct enterpriseSt
{
int energy_level;
int damage;
int torpedo_count;
};
struct klingonSt
{
int energy_level;
int damage;
int position[2];
};
int main()
{
struct enterpriseSt enterprise;
enterprise.energy_level=energy_ent_max;
enterprise.damage=0;
enterprise.torpedo_count=10;
struct klingonSt klingon[100];
main_menu(command,galaxy,turn,&enterprise,&klingon);
return 0;
}
void main_menu(char command, char galaxy[][sz2],int& turn,struct enterpriseSt * enterprise,struct klingonSt * klingon[100])
{
combat_menu(galaxy,enterprise,turn,klingon);
}
I have two structures, enterpriseSt and klingonSt. I can pass enterprise no problem, but with klingon I am struggling. I get all kinds of errors, doesn't matter what combination I use. The current one is:
error: cannot convert ‘klingonSt (*)[100]’ to ‘klingonSt**’ for argument ‘5’ to ‘void main_menu(char, char (*)[64], int&, enterpriseSt*, klingonSt**)’
I've made such a mess with it now. Could someone please explain it to me why it works with enterprise but not with klingon?
I use g++ compiler on Ubuntu. Thanks.
Your problem is in misunderstanding the arguments parsing rules.
you think that struct klingonSt*[100] is a pointer to the array of size 100 of type struct klingonSt, but actually when argument parsing, array and function symbols that should be situated on the right of token has higher priority, than symbols on the left of expression.
So, lets first write the expression with argument name included:
struct klingonSt*var[100]
and parse it
var
is an array of size 100 (as array symbol on the right has higher priority, than pointer on the left)
of pointers
to the type struct klingonSt
so, struct klingonSt*var[100] is actually is array of size 100 of pointers to struct klingonSt.
to pass a pointer to the array of size 100 of type struct klingonSt you should change parsing precedence using parenthesis:
struct klingonSt(*var)[100]
or
struct klingonSt(*)[100]
If you change your definition, your code will compile fine.
I think you're a bit confused on passing arrays to functions. When this is done, the array decays into a pointer to the first element of the array. You can declare the parameter as an array, but the array range is ignored by the compiler, and not enforced at runtime. Thus, for this style of coding, you'd just want to pass the array as a pointer, and length as a separate parameter (I've omitted your other params for clarity):
void main_menu(enterpriseSt*, int enterpriseCount, klingonSt*, int klingonCount);
Some alternatives to consider:
Adopting a modern C++ style, and use std containers like vector/list, passing them by reference.
void main_menu(vector<enterpriseSt> & enterprises, vector<klingonSt> & klingons);
Or, using a template wrapper to pass sized local arrays implicitly:
template<size_t eCount, size_t kCount>
void main_menu(enterpriseSt (&enterprises)[eCount], klingonSt (&klingons)[kCount])
{
main_menu(enterprises, eCount, klingons, kCount);
}
The problem that
struct klingonSt * klingon[100]
is an array of 100 struct klingonSt * rather than a point to 100 struct klingonSt
use struct klingonSt klingon[][100] instead.

Why can I declare a 2D array with both dimensions sized variable but not new one?

As the problem stated, this is doable:
#include <iostream>
int main(int argc, char *argv[])
{
unsigned short int i;
std::cin >> i;
unsigned long long int k[i][i];
}
Here I declared an array that is sized i by i, both dimensions are variables.
But not this:
#include <iostream>
int main(int argc, char *argv[])
{
unsigned short int i;
std::cin >> i;
unsigned long long int** k = new int[i][i];
delete[] k;
}
I got an compiler message telling me that
error: only the first dimension of an allocated array may have dynamic
size
I am forced to do this:
#include <iostream>
int main(int argc, char *argv[])
{
unsigned short int i;
std::cin >> i;
unsigned long long int** k = new unsigned long long int*[i];
for ( unsigned short int idx = 0 ; idx < i ; ++ i )
k[idx] = new unsigned long long int[i];
for ( unsigned short int idx = 0 ; idx < i ; ++ i )
delete[] k[idx];
delete[] k;
}
To my understanding, new and delete are used to allocate something on heap, not on stack, which won't be deleted when it goes out of scope, and is useful for passing datas across functions and objects, etc.
What I don't understand is what happens when I declare that k in the first example, I am told that declared array should (and could) only have constant dimensions, and when in need for a array of unknown size, one should always consider new & delete or vectors.
Is there any pros and cons to those two solutions I'm not getting, or is it just what it is?
I'm using Apple's LLVM compiler by the way.
Neither form is C++ standard compliant, because the standard does not support variable-length arrays (VLAs) (interestingly, C99 does - but C is not C++). However, several compilers have an extension to support this, including your compiler:
From Clang's Manual:
Clang supports such variable length arrays in very limited circumstances for compatibility with GNU C and C99 programs:
The element type of a variable length array must be a POD ("plain old data") type, which means that it cannot have any user-declared constructors or destructors, any base classes, or any members of non-POD type. All C types are POD types.
Variable length arrays cannot be used as the type of a non-type template parameter.
But given that the extension is in place, why doesn't your second snippet work? That's because VLA only applies to automatic variables - that is, arguments or local variables. k is automatic but it's just a pointer - the array itself is defined by new int[i][i], which allocates on the heap and is decidedly not an automatic variable.
You can read more about this on the relevant GCC manual section.
I'm sure you can find implementation for 2D array functionality easily, but you can make your own class too. The simplest way is to use std::vector to hold the data and have an index-mapping function that takes your two coordinates and return a single index into the vector.
The client code will look a little different, instead of arr[x][y] you have arr.at(x,y) but otherwise it does the same. You do not have to fiddle with memory management as that is done by std::vector, just use v.resize(N*N) in constructor or dimension-setting function.
Essentially what compilers generally do with two-dimensional arrays (fixed or variable) is this:
int arr[x][y] ---> int arr[x*y];
arr[2][4]= something ---> arr[2+4*x]= something;
Basically they are just a nicer way of notation of a one-dimensional array (on the stack). Most compilers require fixed sizes, so the compiler has an easier way of telling what the dimensions are (and thus what to multiply with). It appears you have just a compiler, which can keep track of the dimensions (and multipliers) even if you use variables.
Of course you can mimick that with new[] yourself too, but it's not supported by the compiler per se.
Probably for the same reason, i.e. because it would be even harder keeping track of the dimensions, especially when moving the pointers around.
E.g. with a new-pointer you could later write:
newarr= someotherarray;
and someotherarray could be something with even different dimensions. If the compiler did a 2-dim -> one dim translation, he'd have to track all possible size transitions.
With the stack allocated arr above, this isn't necessary, because at least once the compiler made it, it stays that size.

Returning an array ... rather a reference or pointer to an array

I am a bit confused. There are two ways to return an array from a method. The first suggests the following:
typedef int arrT[10];
arrT *func(int i);
However, how do I capture the return which is an int (*)[]?
Another way is through a reference or pointer:
int (*func(int i)[10];
or
int (&func(int i)[10];
The return types are either int (*)[] or int (&)[].
The trouble I am having is how I can assign a variable to accept the point and I continue to get errors such as:
can't convert int* to int (*)[]
Any idea what I am doing wrong or what is lacking in my knowledge?
If you want to return an array by value, put it in a structure.
The Standard committee already did that, and thus you can use std::array<int,10>.
std::array<int,10> func(int i);
std::array<int,10> x = func(77);
This makes it very straightforward to return by reference also:
std::array<int,10>& func2(int i);
std::array<int,10>& y = func2(5);
First, the information you give is incorrect.
You write,
“There are two ways to return an array from a method”
and then you give as examples of the ways
typedef int arrT[10];
arrT *func(int i);
and
int (*func(int i))[10];
(I’ve added the missing right parenthesis), where you say that this latter way, in contrast to the first, is an example of
“through a reference or pointer”
Well, these two declarations mean exactly the same, to wit:
typedef int A[10];
A* fp1( int i ) { return 0; }
int (*fp2( int i ))[10] { return 0; }
int main()
{
int (*p1)[10] = fp1( 100 );
int (*p2)[10] = fp2( 200 );
}
In both cases a pointer to the array is returned, and this pointer is typed as "pointer to array". Dereferencing that pointer yields the array itself, which decays to a pointer to itself again, but now typed as "pointer to item". It’s a pointer to the first item of the array. At the machine code level these two pointers are, in practice, exactly the same. Coming from a Pascal background that confused me for a long time, but the upshot is, since it’s generally impractical to carry the array size along in the type (which precludes dealing with arrays of different runtime sizes), most array handling code deals with the pointer-to-first-item instead of the pointer-to-the-whole-array.
I.e., normally such a low level C language like function would be declared as just
int* func()
return a pointer to the first item of an array of size established at run time.
Now, if you want to return an array by value then you have two choices:
Returning a fixed size array by value: put it in a struct.
The standard already provides a templated class that does this, std::array.
Returning a variable size array by value: use a class that deals with copying.
The standard already provides a templated class that does this, std::vector.
For example,
#include <vector>
using namespace std;
vector<int> foo() { return vector<int>( 10 ); }
int main()
{
vector<int> const v = foo();
// ...
}
This is the most general. Using std::array is more of an optimization for special cases. As a beginner, keep in mind Donald Knuth’s advice: “Premature optimization is the root of all evil.” I.e., just use std::vector unless there is a really really good reason to use std::array.
using arrT10 = int[10]; // Or you can use typedef if you want
arrT10 * func(int i)
{
arrT10 a10;
return &a10;
// int a[10];
// return a; // ERROR: can't convert int* to int (*)[]
}
This will give you a warning because func returns an address of a local variable so we should NEVER code like this but I'm sure this code can help you.

How do I find the length of "char *" array in C?

I declare the following array:
char* array [2] = { "One", "Two"};
I pass this array to a function. How can I find the length of this array in the function?
You can't find the length of an array after you pass it to a function without extra effort. You'll need to:
Use a container that stores the size, such as vector (recommended).
Pass the size along with it. This will probably require the least modification to your existing code and be the quickest fix.
Use a sentinel value, like C strings do1. This makes finding the length of the array a linear time operation and if you forget the sentinel value your program will likely crash. This is the worst way to do it for most situations.
Use templating to deduct the size of the array as you pass it. You can read about it here: How does this Array Size Template Work?
1 In case you were wondering, most people regret the fact that C strings work this way.
When you pass an array there is NOT an easy way to determine the size within the function.
You can either pass the array size as a parameter
or
use std::vector<std::string>
If you are feeling particularly adventurous you can use some advanced template techniques
In a nutshell it looks something like
template <typename T, size_t N>
void YourFunction( T (&array)[N] )
{
size_t myarraysize = N;
}
C is doing some trickery behind your back.
void foo(int array[]) {
/* ... */
}
void bar(int *array) {
/* ... */
}
Both of these are identical:
6.3.2.1.3: Except when it is the operand of the sizeof operator or the unary & operator,
or is a string literal used to initialize an array, an expression that has type
‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’
that points to the initial element of the array object and is not an lvalue. If
the array object has register storage class, the behavior is undefined.
As a result, you don't know, inside foo() or bar(), if you were
called with an array, a portion of an array, or a pointer to a single
integer:
int a[10];
int b[10];
int c;
foo(a);
foo(&b[1]);
foo(&c);
Some people like to write their functions like: void foo(int *array)
just to remind themselves that they weren't really passed an array,
but rather a pointer to an integer and there may or may not be more
integers elsewhere nearby. Some people like to write their functions
like: void foo(int array[]), to better remind themselves of what the
function expects to be passed to it.
Regardless of which way you like to do it, if you want to know how long
your array is, you've got a few options:
Pass along a length paramenter too. (Think int main(int argc, char
*argv)).
Design your array so every element is non-NULL, except the last
element. (Think char *s="almost a string"; or execve(2).)
Design your function so it takes some other descriptor of the
arguments. (Think printf("%s%i", "hello", 10); -- the string describes
the other arguments. printf(3) uses stdarg(3) argument handling, but
it could just as easily be an array.)
Getting the array-size from the pointer isn't possible. You could just terminate the array with a NULL-pointer. That way your function can search for the NULL-pointer to know the size, or simply just stop processing input once it hits the NULL...
If you mean how long are all the strings added togather.
int n=2;
int size=0;
char* array [n] = { "One", "Two"};
for (int i=0;i<n;++i)
size += strlen(array[i];
Added:
yes thats what im currently doing but i wanted to remove that extra
paramater. oh well –
Probably going to get a bad response for this, but you could always use the first pointer to store the size, as long as you don't deference it or mistake it for actually being a pointer.
char* array [] = { (char*)2,"One", "Two"};
long size=(long)array[0];
for(int i=1; i<= size;++i)
printf("%s",array[i]);
Or you could NULL terminate your array
char* array [] = { "One", "Two", (char*)0 };
for(int i=0;array[i]!=0;++i)
{
printf("%s",array[i]);
}
Use the new C++11 std::array
http://www.cplusplus.com/reference/stl/array/
the standard array has the size method your looking for