Passing value of const int in function to initialize array - c++

I understand that arrays need to have a const int to be initialized, so I have this in main. I want this in main because I want to be able to modify these numbers easily if necessary.
const int magicWordCount = 10;
compareWords(magicWordCount);
The declaration of this function is:
void compareWords(const int);
The definition:
void Words::compareWords(const int magicWordCount)
{
std::string magic[magicWordCount] = {};
convertToStringArray(magicBuffer, magicBufferLength);
}
When I do this, "magicWordCount" in the definition is underlined by intellisense telling me, expression must have a constant value. I'm confused on where the value is NOT constant. Thoughts?

Although magicWordCount is const, as far as the compiler knows, it is a run-time constant, not a compile-time constant. In other words, it can ensure that the value of magicWordCount is not going to be changed inside Words::compareWords.
That is not enough to declare an array with the specific size: the compiler (and intellisense) are asking for a compile-time constant; magicWordCount is not a compile-time constant.
You can avoid this problem by using std::vector instead of an array:
std::vector<std::string> magic(magicWordCount);
The above will work even without const.

You could put magicWordCount in your Word class header, above your definition of the class. It's still easily accessible there, and you won't have to pass it in as a function parameter anymore.

it is the problem about array
because array is store in local scope
which mean if it did not have a const size(define before compile) it could make buffer overflow attack
for example the const int magicWordCount = 1000
the size of string[] will absolutely cover the return point
so in this situation you might use pointer instead
string* str = (string*)malloc(sizeof(string*) * a);
for(int i = 0; i < a; i++){str[i] = "";}
and also for my opinion, never use array, and instead with pointer
because the array perform really bad performance and a strange logic on read/write

Related

Function scope regarding pointers in C++ (or C)

I am attempting to write portable code that allows the function to access a variable like an array, even if it is just a single value. The idea behind it is that the code will not make an array of size 1, but I need to be able to loop over all the values in the array if it is an array. Since I can't use sizeof(foo) to determine whether the memory is larger than a single instance sizeof(foo)/sizeof(int) might work, but it is too cumbersome to include in the main code. Macros wouldn't help because if I used a ternary operator like I'd expect #define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo) to return a pointer, in order to access with indexing. This problem is the compiler doesn't like the mixing of types between pointers and non-pointers.
So my second attempt was function overloading.
int * convert(int value)
{return &value;}
int * convert(int * value)
{return value;}
I know that this wouldn't work, because the first function would return the address of the temporary variable copy in that function scope. So my third attempt was
int * convert(int * value)
{return value;}
int * convert(int ** value)
{return *value;}
Every time I would call convert, pass the address of the value: convert(&foo).
This should work, and (I think) it avoids returning a temporary function scope
address. The result of convert would be accessible with indexing. In a controlled for loop, the code would run smoothly. The program would know how many elements are in value, but it would be faster to run everything inside a for loop than not.
So why does my second block of code produce the "Warning returning temporary scope blahblahblah" warning?
UPDATE: Major XY problem here.
Basically I'm trying to wrap all my code in a loop and access each value in a variable, one value per loop iteration. The system would know how many values are in that variable, but the code base is so large that wrapping everything in an if/else would be slow. So the way to access some value in the for loop with an index would be int foo = convert(&maybeArray)[counter]; Then I would use foo several times in the for loop.
For some reason Visual Studio was throwing an error while with the second block of code. Added this to OP.
Another solution would be to make 2 functions with overloaded operators that would basically execute the entire code, without converting each variable, but the code base is very large, and this needs to be as portable as possible. Referencing convert would be more future proof I would believe.
You've tagged this as C++, so I'm assuming you are using a C++ compiler.
There's a lot going on in your question, so I'm going to simplify. You want a C++ function convert(x) that will:
if x is an array, return the address of the first element
if x is not an array, return &x.
(Generally, maybe you need to redesign this whole thing, convert seems like a pretty strange function to want).
template<typename T, size_t N>
auto convert( T (&t) [N] ) -> T* {
return t; // just let pointer decay work for us here
}
template<typename T>
auto convert( T &t) -> T* {
return &t;
}
And, in C++, I would never use sizeof with things that I think are arrays. This template technique is a safer way to count the number of elements in an array.
Also, do you expect to have arrays of pointers, and to want to treat a single pointer as a single-element-array of pointers? If so, then tread carefully. Something that looks like an array, might actually be a pointer, e.g. arrays in parameter lists foo(int is_really_a_pointer[5]) { ...}. See the comment by #MSalters for more. Might be good to use his assert to catch any surprises. If you're just using int, then don't use the typename T in my templates, just force it to be int for clarity.
Finally, maybe instead of turning arrays into pointers, you should ask for a function that turns a non-array into a reference to a single-element array?
Update Here is a more complete example showing how to use convert and convert_end to find the beginning and end of an array to iterate over all the elements in an array; where, of course, a non-array is treated as an array of one element.
In C, there exist only pass by value. When you pass a pointer to a function then its address is copied to the function parameter. This simply means that if p is a pointer in calling function then a function call
int x = 5;
int *p = &x;
int a = foo(p);
for function definition
int foo(int *p1)
{
return *p1*2;
}
is implies that:
copy the address p points to parameter p1, i.e make p and p1 points to the same location.
any changes to the location pointed by p1 in function foo is reflected to *p because p and p1 is pointing to same location. But, if at any point p1 points to another location then this does not imply that p will point to that location too. p and p1 are two different pointers.
When you you pass a pointer to pointer, as in your last snippet of second block,
int * convert(int ** value)
{return *value;}
if *value changes to points to different location after argument is passed to it, then that pointer whose address is passed will also be updated with this location. In this case no need to return *value, but returning do no harm.

Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

This is what I found during my learning period:
#include<iostream>
using namespace std;
int dis(char a[1])
{
int length = strlen(a);
char c = a[2];
return length;
}
int main()
{
char b[4] = "abc";
int c = dis(b);
cout << c;
return 0;
}
So in the variable int dis(char a[1]) , the [1] seems to do nothing and doesn't work at
all, because I can use a[2]. Just like int a[] or char *a. I know the array name is a pointer and how to convey an array, so my puzzle is not about this part.
What I want to know is why compilers allow this behavior (int a[1]). Or does it have other meanings that I don't know about?
It is a quirk of the syntax for passing arrays to functions.
Actually it is not possible to pass an array in C. If you write syntax that looks like it should pass the array, what actually happens is that a pointer to the first element of the array is passed instead.
Since the pointer does not include any length information, the contents of your [] in the function formal parameter list are actually ignored.
The decision to allow this syntax was made in the 1970s and has caused much confusion ever since...
The length of the first dimension is ignored, but the length of additional dimensions are necessary to allow the compiler to compute offsets correctly. In the following example, the foo function is passed a pointer to a two-dimensional array.
#include <stdio.h>
void foo(int args[10][20])
{
printf("%zd\n", sizeof(args[0]));
}
int main(int argc, char **argv)
{
int a[2][20];
foo(a);
return 0;
}
The size of the first dimension [10] is ignored; the compiler will not prevent you from indexing off the end (notice that the formal wants 10 elements, but the actual provides only 2). However, the size of the second dimension [20] is used to determine the stride of each row, and here, the formal must match the actual. Again, the compiler will not prevent you from indexing off the end of the second dimension either.
The byte offset from the base of the array to an element args[row][col] is determined by:
sizeof(int)*(col + 20*row)
Note that if col >= 20, then you will actually index into a subsequent row (or off the end of the entire array).
sizeof(args[0]), returns 80 on my machine where sizeof(int) == 4. However, if I attempt to take sizeof(args), I get the following compiler warning:
foo.c:5:27: warning: sizeof on array function parameter will return size of 'int (*)[20]' instead of 'int [10][20]' [-Wsizeof-array-argument]
printf("%zd\n", sizeof(args));
^
foo.c:3:14: note: declared here
void foo(int args[10][20])
^
1 warning generated.
Here, the compiler is warning that it is only going to give the size of the pointer into which the array has decayed instead of the size of the array itself.
The problem and how to overcome it in C++
The problem has been explained extensively by pat and Matt. The compiler is basically ignoring the first dimension of the array's size effectively ignoring the size of the passed argument.
In C++, on the other hand, you can easily overcome this limitation in two ways:
using references
using std::array (since C++11)
References
If your function is only trying to read or modify an existing array (not copying it) you can easily use references.
For example, let's assume you want to have a function that resets an array of ten ints setting every element to 0. You can easily do that by using the following function signature:
void reset(int (&array)[10]) { ... }
Not only this will work just fine, but it will also enforce the dimension of the array.
You can also make use of templates to make the above code generic:
template<class Type, std::size_t N>
void reset(Type (&array)[N]) { ... }
And finally you can take advantage of const correctness. Let's consider a function that prints an array of 10 elements:
void show(const int (&array)[10]) { ... }
By applying the const qualifier we are preventing possible modifications.
The standard library class for arrays
If you consider the above syntax both ugly and unnecessary, as I do, we can throw it in the can and use std::array instead (since C++11).
Here's the refactored code:
void reset(std::array<int, 10>& array) { ... }
void show(std::array<int, 10> const& array) { ... }
Isn't it wonderful? Not to mention that the generic code trick I've taught you earlier, still works:
template<class Type, std::size_t N>
void reset(std::array<Type, N>& array) { ... }
template<class Type, std::size_t N>
void show(const std::array<Type, N>& array) { ... }
Not only that, but you get copy and move semantic for free. :)
void copy(std::array<Type, N> array) {
// a copy of the original passed array
// is made and can be dealt with indipendently
// from the original
}
So, what are you waiting for? Go use std::array.
It's a fun feature of C that allows you to effectively shoot yourself in the foot if you're so inclined. I think the reason is that C is just a step above assembly language. Size checking and similar safety features have been removed to allow for peak performance, which isn't a bad thing if the programmer is being very diligent. Also, assigning a size to the function argument has the advantage that when the function is used by another programmer, there's a chance they'll notice a size restriction. Just using a pointer doesn't convey that information to the next programmer.
First, C never checks array bounds. Doesn't matter if they are local, global, static, parameters, whatever. Checking array bounds means more processing, and C is supposed to be very efficient, so array bounds checking is done by the programmer when needed.
Second, there is a trick that makes it possible to pass-by-value an array to a function. It is also possible to return-by-value an array from a function. You just need to create a new data type using struct. For example:
typedef struct {
int a[10];
} myarray_t;
myarray_t my_function(myarray_t foo) {
myarray_t bar;
...
return bar;
}
You have to access the elements like this: foo.a[1]. The extra ".a" might look weird, but this trick adds great functionality to the C language.
To tell the compiler that myArray points to an array of at least 10 ints:
void bar(int myArray[static 10])
A good compiler should give you a warning if you access myArray [10]. Without the "static" keyword, the 10 would mean nothing at all.
This is a well-known "feature" of C, passed over to C++ because C++ is supposed to correctly compile C code.
Problem arises from several aspects:
An array name is supposed to be completely equivalent to a pointer.
C is supposed to be fast, originally developerd to be a kind of "high-level Assembler" (especially designed to write the first "portable Operating System": Unix), so it is not supposed to insert "hidden" code; runtime range checking is thus "forbidden".
Machine code generrated to access a static array or a dynamic one (either in the stack or allocated) is actually different.
Since the called function cannot know the "kind" of array passed as argument everything is supposed to be a pointer and treated as such.
You could say arrays are not really supported in C (this is not really true, as I was saying before, but it is a good approximation); an array is really treated as a pointer to a block of data and accessed using pointer arithmetic.
Since C does NOT have any form of RTTI You have to declare the size of the array element in the function prototype (to support pointer arithmetic). This is even "more true" for multidimensional arrays.
Anyway all above is not really true anymore :p
Most modern C/C++ compilers do support bounds checking, but standards require it to be off by default (for backward compatibility). Reasonably recent versions of gcc, for example, do compile-time range checking with "-O3 -Wall -Wextra" and full run-time bounds checking with "-fbounds-checking".
C will not only transform a parameter of type int[5] into *int; given the declaration typedef int intArray5[5];, it will transform a parameter of type intArray5 to *int as well. There are some situations where this behavior, although odd, is useful (especially with things like the va_list defined in stdargs.h, which some implementations define as an array). It would be illogical to allow as a parameter a type defined as int[5] (ignoring the dimension) but not allow int[5] to be specified directly.
I find C's handling of parameters of array type to be absurd, but it's a consequence of efforts to take an ad-hoc language, large parts of which weren't particularly well-defined or thought-out, and try to come up with behavioral specifications that are consistent with what existing implementations did for existing programs. Many of the quirks of C make sense when viewed in that light, particularly if one considers that when many of them were invented, large parts of the language we know today didn't exist yet. From what I understand, in the predecessor to C, called BCPL, compilers didn't really keep track of variable types very well. A declaration int arr[5]; was equivalent to int anonymousAllocation[5],*arr = anonymousAllocation;; once the allocation was set aside. the compiler neither knew nor cared whether arr was a pointer or an array. When accessed as either arr[x] or *arr, it would be regarded as a pointer regardless of how it was declared.
One thing that hasn't been answered yet is the actual question.
The answers already given explain that arrays cannot be passed by value to a function in either C or C++. They also explain that a parameter declared as int[] is treated as if it had type int *, and that a variable of type int[] can be passed to such a function.
But they don't explain why it has never been made an error to explicitly provide an array length.
void f(int *); // makes perfect sense
void f(int []); // sort of makes sense
void f(int [10]); // makes no sense
Why isn't the last of these an error?
A reason for that is that it causes problems with typedefs.
typedef int myarray[10];
void f(myarray array);
If it were an error to specify the array length in function parameters, you would not be able to use the myarray name in the function parameter. And since some implementations use array types for standard library types such as va_list, and all implementations are required to make jmp_buf an array type, it would be very problematic if there were no standard way of declaring function parameters using those names: without that ability, there could not be a portable implementation of functions such as vprintf.
It's allowed for compilers to be able to check whether the size of array passed is the same as what expected. Compilers may warn an issue if it's not the case.

Declare array with declared constant

I'm trying to do something like this:
const int array_size = 5;
string stuff[array_size];
My compiler won't let me compile this, even though array_size is a constant. Is there a way to do this without dealing with dynamic arrays?
Edit: "error C2057: expected constant expression"
I have answered this question assuming you are either coding in C or C++. If you are using a different language, this answer doesn't apply. However, you should update your question with the language you are trying to use.
Consider the following program:
int main () {
const int size = 5;
int x[size];
return 0;
}
This will compile in both C++ and C.99, but not C.89. In C.99, variable length arrays were introduced, and so locally scoped arrays can take on a size specified by a variable. However, arrays at file scope in C.99 cannot take a variable size parameter, and in C.89, all array definitions have to have a non variable size.
If you are using C.89, or defining a file scope array in C.99, you can use an enum to name your constant value. The enum can then be used to size the array definition. This is not necessary for C++ however, which allows a const integer type initialized by a literal to be used to size an array declaration.
enum { size = 5 };
int x[size];
int main () { return 0; }
#define array_size 5
string stuff[array_size];
You can use e.g. a vector or the new keyword to allocate memory dynamically, because declared arrays can not have runtime sizes.
Only thing I can think of is that you defined another array_size variable in your code, which is not a compile time constant and hides the original array_size.
array_size is not treated as a compile time constant. Constness added just makes sure that programmer can not modify it. If tried to modify accidentally, compiler will bring to your attention.
Size of an array needs to be a compile constant. Seems like your compiler is not supporting Variable Length Array. You can #define the size of the array instead which is treated as a constant expression.

Prefered way to declare pointer/reference variables?

Note: I am using the g++ compiler (which is I hear is pretty good and supposed to be pretty close to the standard).
Not trying to start a grammar war, but just a random question... What is the ideal way to declare a pointer?
int* pI = 4;
int *pI = 4;
(or my favorite, I know it's non-pretty, but I like it):
int*pI = 4;
Same question stands for references:
int& rI = 4;
int &rI = 4;
or
int&rI = 4;
Maybe there is no right answer. Similarly, should I care whether a constant integer is declared as:
const int I = 4;
or
int const I = 4;
I'm fine with not caring...
I do like the way a const function is declared by having a const after the last parenthesis.
And I believe a constant function has a distinct function signature than the similar non-const function (i.e. the const-nesss is part of the function signature, unlike most sources that say it just depends on the arguments type and the return type).
Is this right? Should I care?
I prefer
int* a;
int& b;
for the following reason: the type is int* and not int. For me - the type belongs together and needs to stand separate from the name. I know this introduces some problems with
int* a, b;
but that's why I don't declare to variables in one line.
Other than that - like VJo said: stick to the coding standard. If everyone around you does it one way, don't do it the other.
Coding standards might tell you how to declare or define your variables.
Other then that, use whatever suits you better.
And I believe a constant function has a distinct function signature than the similar non-const function (i.e. the const-nesss is part of the function signature, unlike most sources that say it just depends on the arguments type and the return type).
A constant function has a keyword const which is appended at the end of it.
int doSomething() const;
It means that the function will not alter the state(members) of the class.
Mentioning const on an argument implies that the function will not alter the state of that variable(param in below example) being passed to the function.
int doSomething(const int param);
Mentioning const before the return type applies to the type being returned by the function.
const int doSomething();
Implies the function returns a const integer value.
So yes your understanding is correct. And there is no other way to declare a function const except putting a const after the last paranthesis.
Also, note that const member function can be only called on a const object, while a non const member function can be called by const as well as non const objects of that class.
As far as the way of declaring, Each organization have their own coding guidelines and you should stick to that, Yes there is no distinct advantage of using those contructs you mentioned in either way with respect to compiler optimization or treatment. Just follow what you like or what your organzation wants you to follow.
Bjarne Stroustrup uses:
int* a;
so, that's good enough for me.

Regarding two dimensional array

I have some problems using two dimensional array.
static const int PATTERNS[20][4];
static void init_PATTERN()
{
// problem #1
int (&patterns)[20][4] = const_cast<int[20][4]>(PATTERNS);
...
}
extern void UsePattern(int a, const int** patterns, int patterns_size);
// problem #2
UsePattern(10, PATTERNS, sizeof(PATTERNS)/sizeof(PATTERNS[0]));
In the first statement, I need to cast the const off the two dimensional array PATTERNS. The reason for this is that the init function is called only once, and in the remaining code, PATTERNS is strictly read-only.
In the second statement, I need to pass PATTERNS array to the int** argument. Direct passing resulted a compile error.
I have solved the problem, just about the same time that #Andrey posted the answer. Yes int[][] can't be casted to int**.
It can be casted to int* through &(PATTERNS[0][0]), and the function prototype must be modified with row size (the number of elements in a row). The array can be const_cast away with reference syntax.
Firstly, there's no such thing as cast to array type (or to function type) in C++. Yet this is what you are trying to do. If you want to cast away constness from something, you have to cast to either pointer or reference type. In your case you have a reference on the receiving end of the cast, so the cast itself has to be to reference type as well
int (&patterns)[20][4] = const_cast<int (&)[20][4]>(PATTERNS);
Of course, as Bill already noted, casting away constness from a constant object (and then attempting to modify the object) leads to undefined behavior.
Secondly, a two-dimensional array cannot be passed anywhere as an int ** pointer. If you want to pass your PATTERNS somewhere, you can pass it as const int (&)[20][4], const int (*)[20][4], const int [][4], const int (*)[4] or something similar to that, but not as int **. Do a search on SO and/or read some FAQ on arrays to understand why. This has been explained too many times to repeat it again.
When you declare PATTERNS as const, the compiler may set it up in read-only memory. You can't safely cast away const unless the item was originally declared without const.
I'm guessing that your compiler error was cannot convert 'int (*)[4]' to 'int**' for argument '2' to 'void UsePattern(int, int**, int)'?
AndreyT's answer is perfect. I'd only like to add that I believe you would be better using a class that does the init_PATTERN() work in the constructor and overrides the operator[] to give readonly access to the array elements.
This, of course, assuming you can change the UsePattern function to get a reference to such class instead of a pointer to int array.
C++ Arrays are complicated. You can't just throw them around and expect them to work like in some languages. The only way to initialize an array from another array is to navigate a for loop and copy each item individually. This goes doubly for two-dimensional arrays (meaning you'll need two for loops).
It seems like you're trying to make this more complicated than it needs to be. For instance, if the set of values you will be assigning to PATTERNS will be the same every time you run the program, you can initialize a two dimensional variable like this:
static const int foo[2][3] = {{11,12,13},{21,22,23}};
If the set of values assigned to PATTERNS varies from one execution to the next, then you should probably try to find a different way to approach the problem. I would probably wrap the data in a class, especially if your intention is to use similarly-sized two-dimensional arrays elsewhere in the code.