This is possible in C++:
const char* ch = "hello";
But something like this is not possible:
int* i = { 1, 2, 3 };
Both char *ch and int* i are plain pointers. Why can char* be assigned with multiple chars while int* can not be assigned with multiple ints?
I know we can use
int x[] = {1, 2, 3};
but that is not the question.
const char* ch = "hello";
is sort of like
static const char string_literal[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
const char* ch = &string_literal[0];
except that each identical string literal does not necessarily point to a distinct location in memory.
The same is also possible for any other type:
static int integer_list[] = { 1, 2, 3 };
int* i = &integer_list[0];
// or equivalently, just int* i = integer_list;
Now, i[0] is 1, i[1] is 2, and i[2] is 3.
There is a special syntax for string literals, because they are so frequently used, and so frequently in contexts where it is not desirable to clutter the code with dummy variables.
If you've got a lot of code that uses statically allocated read-only arrays of integer type, you may be able to hide the boilerplate using templates:
template <int a, int b, int c>
struct int_array { static const int values[3]; };
template <int a, int b, int c>
const int int_array<a, b, c>::values[] = { a, b, c };
You only need to define the template once, and then each different user can use that template for the specific values that user is interested in.
const int* i = int_array<1, 5, 6>::values;
Often, it will be easier to simply define a separate array variable, but there are cases where such a template helps.
As noted in the comments, it's possible to define the template more generically, so that it works for arrays of arbitrary type and arbitrary length, but it requires an up-to-date compiler with good support for the current version of C++ (for GCC and clang, current versions are fine, but make sure to pass the -std=c++11 or -std=gnu++11 option to enable C++11 features):
template <typename T, T... v>
struct static_array {
static const T values[sizeof...(v)];
};
template <typename T, T... v>
const T static_array<T, v...>::values[sizeof...(v)] = { v... };
Now, the syntax for a user of this array is
const int* i = static_array<int, 1, 2, 3, 4>::values;
const unsigned* j = static_array<unsigned, 1, 2, 3, 4, 5>::values;
A string literal is an array of characters. Note that ch is just a pointer to a single character so it really doesn't point to the string as a whole but just its base address (the address of the first character). An initializer-list (i.e {1, 2, 3}) is not an array, and therefore can't be used to initialize the pointer.
The character literal is compiled to a piece of initialized storage in the data segment of your binary. The const char * is a pointer to that storage.
As a matter of fact, it should be possible to do the same for an const int *, if only you had the address of a memory block. You could do this using inline assembler (but I never tried) specifying a .data segment.
Related
I asked this question: Array Equivalent of Bare-String
To which the answer was C++ doesn't provide this functionality for const int*s. Which is disappointing. So my question then is: In practice how do I get around this limitation?
I want to write a struct like this:
struct foo{
const char* letters = "abc";
const int* numbers = ???
};
I cannot:
&{1, 2, 3} cause I can't take the address of an r-value
array<int, 3>{{1, 2, 3}}.data() cause the memory is cleaned up immediately after initialization
const int* bar(){ return new int[3]{1, 2, 3}; } cause nothing will delete this pointer
I know that I can use an auto pointer to get around this. I am not suggesting that struct foo is good code, I am trying to illustrate that the compiler makes a provision to store the const array "abc" in memory and clean it up on program exit, I want there to be a way to do that for ints as well.
Is there a way to accomplish this?
How about a static which you point to - I think this what the compiler pretty much does internally for "strings literals" anyway?
static const int Numbers[] = {1, 2, 3};
struct foo{
const char* letters = "abc";
const int* numbers = Numbers;
};
String literals are all you get. However, they are also enough to cover most integral data. In your case you can use
L"\1\2\3"
to get a compiler-managed array of wide characters. C++11 and later also support u8, u16, and u32 strings.
We can accomplish this using Ben Voigt's answer:
const int* numbers = sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U"\1\2\3") : reinterpret_cast<const int*>(u"\1\2\3");
The ternary is compiled out as is evidenced by the fact that you can declare numbers as constexpr.
There are a couple drawbacks to this implementation:
This is actually a wchar_t string literal you will get a terminating 0 element in addition to any characters you specify
This assumes that an int will be either 32-bits or 16-bits, if that's not the case this will try to cast from a char16_t to a whatever sized int and you will have major problems
In any case we can simplify this into a macro:
#define QUOTATION(x) sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U ## x) : reinterpret_cast<const int*>(u ## x)
Which can be used like:
const int* numbers = QUOTATION("\1\2\3");
I was thinking about this the other day and I am curious if this is a bad idea...
Lets say there is a structure that contains a pointer to a string array.
Would the memcpy() copy the 'name' array pointer in the below example?
Edit: The std is inaccessible in this example.
struct charMap
{
unsigned char * name;
unsigned char id;
};
typedef struct charMap CharMapT;
class ABC
{
public:
ABC(){}
void Function();
CharMapT* structList;
}
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
structList = new CharMapT[sizeof(list)];
memcpy(structList, &list, sizeof(list));
}
There are several errors in the code presented, which I will talk about first, followed by my stock-diatribe of pointers vs. arrays.
struct charMap
{
unsigned int * name;
unsigned int id;
};
typedef struct charMap CharMapT;
This declares a structure type that includes a pointer to unsigned int as the first member (name) and an int as the second member (id). On a 32-bit system with default byte packing this will be 8 bytes wide (32-bit pointer = 4bytes, 32-bit signed int=4bytes). If this is a 64-bit machine the pointers will be 8 bytes wide, the int still-likely 32-bits wide, making the structure size 12 bytes.
Questionable Code
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
structList = new CharMapT[sizeof(list)];
memcpy(structList, &list, sizeof(list));
}
This allocates dynamic array of CharMapT structs. How many? More than you think. The sizeof(list) will return the byte-count of the list[] array. Since a CharMapT structure is 8 bytes wide (see above) this will 3 * 8, or 24 CharMapT items (36 items if using 64-bit pointers).
We then memcpy() 24 bytes (or 36 bytes) from list (the & in &list is unecessary) to the newly allocated memory. this will copy over 3 CharMapT structures, leaving the other 21 we allocated untouched (beyond their initial default construction).
Note: you're initializing a const char * to a field declared as unsigned int *, so if this even compiled the fundamental data type would be different. Assuming you fixed your structure and change the pointer type to const char *, the addresses of the static string constants (the addresses of the "NAME" constants) somewhere in your const data segment will be assigned to the pointer variables of the elements in structList[0].name, structList[2].name, and structList[3].name respectively.
This will NOT copy the data pointed to. it will only copy the pointer values. If you want copies of the data then you must raw-allocate them (malloc, new, whatever).
Better still, use an std::vector<CharMapT>, use std::string for CharMapT::name, and use std::copy() to replicate the source (or even direct-assignment).
I hope that explains what you were looking for.
Pointer vs. Array Diatribe
Never confuse a pointer with an array. A pointer is a variable that holds an address. Just like an int variable hold an integer value, or a char variable holds a character type, the value held in a pointer is an address
An array is different. It is also a variable (obviously), but it cannot be an l-value, and nearly every place it is typically used a conversion happens. Conceptually that conversion results in a temporary pointer that points to the data type of the array, and holds the address of the first element. There are times when that concept does not happen (such as the applying the address-of operator).
void foo(const char * p)
{
}
char ar[] = "Hello, World!";
foo(ar); // passes 'ar', converted to `char*`, into foo.
// the parameter p in foo will *hold* this address
or this:
char ar[] = "Goodbye, World!";
const char *p = ar; // ok. p now holds the address of first element in ar
++p; // ok. address in `p` changed to address (ar+1)
but not this:
char ar[] = "Goodbye, World!";
++ar; // error. nothing to increment.
It won't copy your actual data pointed by name. It will copy the pointer and you'll have 2 pointers to the same place in 2 objects (for each pair of objects in 2 arrays).
All you really need to know here is that memcpy will give you a bit for bit copy of the original. So what you'll have is two pointers with the same value (i.e., an address) which refer to the same data.
On a side note, you have declared name as a pointer to int, which is of course wrong here. It should be a const char*. Also, as this is C++ and not C, you're better served by something like std::copy which won't break your code subtly if charMap someday becomes a complex type. On the same note, prefer std::string instead of const char* in most situations.
Your use of sizeof() is wrong when calling new. You are allocating an array of CharMapT elements. You have to specify the number of elements, but you are specifying a byte count instead. So you need to fix that:
structList = new CharMapT[sizeof(list) / sizeof(CharMapT)];
With that fixed, the result of the memcpy() will be that structList will contains an exact copy of the raw data that list[] contains. That means that the structList[N].name pointers will contain the same values as the list[N].name pointers, and thus they will all be pointing at the same physical memory for the string values.
If you want to do a deep copy of the string values, you have to allocate them separately, eg:
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
int num = sizeof(list) / sizeof(CharMapT);
structList = new CharMapT[num];
for (int i = 0; i < num; ++i)
{
int len = strlen(list[i].name);
structList[i].name = new char[len+1];
strcpy(structList[i].name, list[i].name);
structList[i].name[len] = 0;
structList[i].id = list[i].id;
}
...
for (int i = 0; i < num; ++i)
delete[] structList[i].name;
delete[] structList;
}
I'd like to add to #EdS.'s answer:
Your code is just much more c++ than c-style c++ code if you do it like this:
#include<string>
#include<vector>
struct CharMap
{
CharMap(const std::string& name, unsigned char id); // only needed if you don't use -std=c++11
std::string name;
unsigned char id;
};
CharMap::CharMap(const std::string& name, unsigned char id):
name(name),
id(id)
{}
class ABC
{
public:
ABC(); // or ABC() = default; if you use -std=c++11
void Function();
private:
std::vector<CharMap> structList;
}
ABC::ABC(){} // not needed with -std=c++11
void ABC::Function ()
{
// This works with -std=c++11:
//structList =
//{
// {"NAME1", 1},
// {"NAME2", 2},
// {"NAME3", 3}
//};
// without c++11:
structList = std::vector<CharMap>(3);
structList[0] = CharMap("NAME1",1); // don't worry about copies, we have RVO (check wikipedia or SO)
structList[1] = CharMap("NAME2",2);
structList[2] = CharMap("NAME2",3);
}
Why not using std::vector for making an array? You can do that like this:
#include<vector>
std::vector<CharMapT> structList(list.size());
It is safer, too, avoiding using pointers decreases the chance of memory leaks or bugs arising due to wrongly using the sizeof operator.
I suppose you do not really want a structList, that has as many elements as the memory size of your list. (If list is double this could be many times more than the number of elements in your list.)
Also, memcpy is really not necessary, if list is also a vector (that is a c function really). You just do a simple assign operation:
structList = list; // given that list is a vector.
This will copy the elements like memcpy.
In the following code why is that the two statements are illegal
const int i[] = { 1, 2, 3, 4 };
// float f[i[3]]; // Illegal
struct S { int i, j; };
const S s[] = { { 1, 2 }, { 3, 4 } };
//double d[s[1].j]; // Illegal
int main() {}
Why are they illegal? The textual definition is as follows which i didn't understand.
"In an array definition, the compiler must be able to generate code
that moves the stack pointer to accommodate the array. In both of the
illegal definitions above, the compiler complains because it cannot
find a constant expression in the array definition."
Thanks in advance.
Array sized need to be constant expressions. Try this:
constexpr int i[] = { 1, 2, 3, 4 };
float f[i[3]];
The constexpr keyword was introduced in C++11. Previous versions of C++ had no concept of such general constant expressions, and there was no equivalent concept.
Because C++ doesn't support variable-length arrays, and s[1].j is not a compile-time constant.
What that quote refers to is the fact that f and d are in automatic storage. The run-time will clean their memory automatically when they go out of scope. As such, it must know the size beforehand.
because d is static array, that means that it's size has to be know at compilation time.
Therefore you can't use non-const variables as size parameter.
But you can try
const int i = 3;
double d[i];
for example.
I'm using a library which for one certain feature involves variables like so:
extern const u8 foo[];
extern const u8 bar[];
I am not allowed to rename these variables in any way.
However, I like to be able to access these variables through an array (or other similar method) so that I do not need to continually hardcode new instances of these variables into my main code.
My first attempt at creating an array is as follows:
const u8* pl[] = {
&foo,
&bar
};
This gave me the error cannot convert 'const u8 (*)[]' to 'const u8*' in initialization, and with help elsewhere along with some Googling, I changed my array to this:
u8 (*pl)[] = {
&foo,
&bar
};
Upon compiling I now get the error scalar object 'pl' requires one element in initializer.
Does anyone have any ideas on what I'm doing wrong? Thanks.
An array of pointers to arrays only works if foo and bar have exactly the same size, and that size is known at compile time in your translation unit.
const u8 (*pl[])[32] = {&foo, &bar};
If that is not the case, you must use an array of pointers to bytes.
const u8 *pl[] = {foo, bar};
As the arrays don't have a size in their declaration is there any reason you can't just an array of pointers to their first elements?
E.g.
const u8* pl[] = { foo, bar };
If you wanted an array of pointers to arrays I think that you would need to do:
const u8 (*pl[])[] = { &foo, &bar };
but I don't see that it really has any advantage over the previous solution.
extern const int a[];
const int * aa[] = { a };
Remove the &. An array decays normally into a pointer.
typedef int u8; // Using int as I don't know what a u8 is.
const u8 foo[] = { 1, 2, 3};
const u8 bar[] = { 1 };
const u8* pl[] = {
foo,
bar
};
This question already has answers here:
How do I find the length of an array?
(30 answers)
Closed 2 years ago.
I have
int list[] = {1, 2, 3};
How to I get the size of list?
I know that for a char array, we can use strlen(array) to find the size, or check with '\0' at the end of the array.
I tried sizeof(array) / sizeof(array[0]) as some answers said, but it only works in main? For example:
int size(int arr1[]){
return sizeof(arr1) / sizeof(arr1[0]);
}
int main() {
int list[] = {1, 2, 3};
int size1 = sizeof(list) / sizeof(list[0]); // ok
int size2 = size(list_1); // no
// size1 and size2 are not the same
}
Why?
Try this:
sizeof(list) / sizeof(list[0]);
Because this question is tagged C++, it is always recommended to use std::vector in C++ rather than using conventional C-style arrays.
An array-type is implicitly converted into a pointer-type when you pass it to a function.
Have a look at this.
In order to correctly print the sizeof an array inside any function, pass the array by reference to that function (but you need to know the size of that array in advance).
You would do it like so for the general case
template<typename T,int N>
//template argument deduction
int size(T (&arr1)[N]) //Passing the array by reference
{
return sizeof(arr1)/sizeof(arr1[0]); //Correctly returns the size of 'list'
// or
return N; //Correctly returns the size too [cool trick ;-)]
}
The "standard" C way to do this is
sizeof(list) / sizeof(list[0])
You could use boost::size, which is basically defined this way:
template <typename T, std::size_t N>
std::size_t size(T const (&)[N])
{
return N;
}
Note that if you want to use the size as a constant expression, you'll either have to use the sizeof a / sizeof a[0] idiom or wait for the next version of the C++ standard.
You can't do that for a dynamically allocated array (or a pointer). For static arrays, you can use sizeof(array) to get the whole array size in bytes and divide it by the size of each element:
#define COUNTOF(x) (sizeof(x)/sizeof(*x))
To get the size of a dynamic array, you have to keep track of it manually and pass it around with it, or terminate it with a sentinel value (like '\0' in null terminated strings).
Update: I realized that your question is tagged C++ and not C. You should definitely consider using std::vector instead of arrays in C++ if you want to pass things around:
std::vector<int> v;
v.push_back(1);
v.push_back(2);
std::cout << v.size() << std::endl; // prints 2
Since you've marked this as C++, it's worth mentioning that there is a somewhat better way than the C-style macro:
template <class T, size_t N>
size_t countof(const T &array[N]) { return N; }
This has the advantage that if you accidentally try to pass something other than an array to it, the code simply won't compile (whereas passing a pointer to the C macro will compile but produce a bad result. The disadvantage is that this doesn't give you a compile-time constant, so you can't do something like this:
int a[20];
char x[countof(a)];
In C++11 or newer, you can add constexpr to get a compile-time constant:
template <class T, size_t N>
constexpr size_t countof(const T &array[N]) { return N; }
If you really want to support the same on older compilers, there is a way, originally invented by Ivan Johnson, AFAIK:
#define COUNTOF(x) ( \
0 * sizeof( reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(x) ) + \
0 * sizeof( ::Bad_arg_to_COUNTOF::check_type((x), &(x)) ) + \
sizeof(x) / sizeof((x)[0]) )
class Bad_arg_to_COUNTOF
{
public:
class Is_pointer;
class Is_array {};
template<typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
This uses sizeof(x)/sizeof(x[0]) to compute the size, just like the C macro does, so it gives a compile-time constant. The difference is that it first uses some template magic to cause a compile error if what you've passed isn't the name of an array. It does that by overloading check_type to return an incomplete type for a pointer, but a complete type for an array. Then (the really tricky part) it doesn't actually call that function at all -- it just takes the size of the type the function would return, which is zero for the overload that returns the complete type, but not allowed (forcing a compile error) for the incomplete type.
IMO, that's a pretty cool example of template meta programming -- though in all honesty, the result is kind of pointless. You really only need that size as a compile time constant if you're using arrays, which you should normally avoid in any case. Using std::vector, it's fine to supply the size at run-time (and resize the vector when/if needed).
Besides Carl's answer, the "standard" C++ way is not to use a C int array, but rather something like a C++ STL std::vector<int> list which you can query for list.size().
when u pass any array to some function. u are just passing it's starting address, so for it to work u have to pass it size also for it to work properly. it's the same reason why we pass argc with argv[] in command line arguement.
You can make a template function, and pass the array by reference to achieve this.
Here is my code snippet
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType);
int main()
{
char charArray[] = "my name is";
int intArray[] = { 1,2,3,4,5,6 };
double doubleArray[] = { 1.1,2.2,3.3 };
PrintArray(charArray);
PrintArray(intArray);
PrintArray(doubleArray);
}
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType)
{
int elementsCount = sizeof(arrayOfType) / sizeof(arrayOfType[0]);
for (int i = 0; i < elementsCount; i++)
{
cout << "Value in elements at position " << i + 1 << " is " << arrayOfType[i] << endl;
}
}
You have to use sizeof() function.
Code Snippet:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int arr[] ={5, 3, 6, 7};
int size = sizeof(arr) / sizeof(arr[0]);
cout<<size<<endl;
return 0;
}
int arr1[] = {8, 15, 3, 7};
int n = sizeof(arr1)/sizeof(arr1[0]);
So basically sizeof(arr1) is giving the size of the object being pointed to, each element maybe occupying multiple bits so dividing by the number of bits per element (sizeof(arr1[0]) gives you the actual number of elements you're looking for, i.e. 4 in my example.
This method work when you are using a class: In this example you will receive a array, so the only method that worked for me was these one:
template <typename T, size_t n, size_t m>
Matrix& operator= (T (&a)[n][m])
{
int arows = n;
int acols = m;
p = new double*[arows];
for (register int r = 0; r < arows; r++)
{
p[r] = new double[acols];
for (register int c = 0; c < acols; c++)
{
p[r][c] = a[r][c]; //A[rows][columns]
}
}
https://www.geeksforgeeks.org/how-to-print-size-of-an-array-in-a-function-in-c/
Assuming you merely want to know the size of an array whose type you know (int) but whose size, obviously, you don't know, it is suitable to verify whether the array is empty, otherwise you will end up with a division by zero (causing a Float point exception).
int array_size(int array[]) {
if(sizeof(array) == 0) {
return 0;
}
return sizeof(array)/sizeof(array[0]);
}
If you want to know how much numbers the array have, you want to know the array length. The function sizeof(var) in C gives you the bytes in the computer memory. So if you know the memory the int occupy you can do like this:
int arraylength(int array[]) {
return sizeof(array) / sizeof(int); // Size of the Array divided by the int size
}