Here's a function prototype:
void foobar(char* array[]);
But how would I call this function, and with what arguments? Could someone give me a simple example?
Quoting from c-faq (as array name conversion rule to pointers is same in C and C++ both):
Since arrays decay immediately into pointers, an array is never actually passed to a function. You can pretend that a function receives an array as a parameter, and illustrate it by declaring the corresponding parameter as an array:
void f(char a[])
{ ... }
Interpreted literally, this declaration would have no use, so the compiler turns around and pretends that you'd written a pointer declaration, since that's what the function will in fact receive:
void f(char *a)
{ ... }
Therefore
void foobar(char* array[]);
is equivalent to
void foobar(char** array);
You need to pass an argumant of type char ** to this function.
Thanks for the reply and comments. Here is what I came up with and it seems to work. Not quite sure why it does, though. Could someone confirm that this is indeed 'correct' code:
void foobar(char* array[]);
void main() {
char* t[3];
t[0] = "first";
t[1] = "second";
t[2] = "third";
foobar(t);
}
void foobar(char* array[]) {
cout << *(array + 0) << endl;
cout << *(array + 1) << endl;
cout << *(array + 2) << endl;
}
The output is:
first
second
third
Related
I am just learning C++ and a little confused about arrays and references. I wrote the following program:
void printArray(int arr[]) {
cout << arr[0] << arr[1] << arr[2] << endl;
}
int main() {
int arr[3] = {5, 7, 9};
int *aPtr = &arr[0];
cout << aPtr[0] << aPtr[1] << aPtr[2] << endl;
int *bPtr = arr;
cout << bPtr[0] << bPtr[1] << bPtr[2] << endl;
printArray(arr);
}
The output is :
579
579
579
And I have two questions:
Is array in C++ a reference? I mean, can I state that i = &i[0]?
If answer to the first question is yes, can I say that as array is reference we don't need to use & in arguments of the function printArray. I mean, we don't declare the function this way printArray(int &arr[])?
No, an array is not a reference in C++. It is an array, the length of which forms part of the type (so for example the type of int[3] is not the same as that of int[42]).
What can be confusing is that C++ inherits from C the strange features that
array function parameters have their type "adjusted" to pointer
array names can "decay" to pointers very easily. That makes it possible to assign an array to a pointer.
Point 1 above means that these two function declarations are completely equivalent:
// two ways do declaring the same function
void foo(int a[42]);
void foo(int* a);
and point 2 means you can call the function passing it an array:
int a[3] = {};
int b[100] = {};
foo(a);
foo(b);
and other funny stuff, for example, the type of expression +a being int*.
I'm teaching myself C++ and had some questions about arrays and pointers. My understanding is that arrays are really just pointers, however, arrays are address constants which cannot be changed.
If this is the case, I was wondering why in my function show2() I was able to change the address of the pointer list. Unlike variables, I thought arrays are passed by reference so I was expecting a compiler error when calling function show2() since I incremented the address of list. But the code works just fine. Can someone please explain?
Thank you!
#include<iostream>
#include<iomanip>
using namespace std;
void show1(double *list, int SIZE)
{
for(int i=0; i < SIZE; i++)
{
cout << setw(5) << *(list+i);
}
cout << endl;
return;
}
void show2(double *list, int SIZE)
{
double *ptr = list;
for(int i=0; i < SIZE; i++)
cout << setw(5) << *list++;
cout << endl;
return;
}
int main()
{
double rates[] = {6.5, 7.2, 7.5, 8.3, 8.6,
9.4, 9.6, 9.8, 10.0};
const int SIZE = sizeof(rates) / sizeof(double);
show1(rates, SIZE);
show2(rates, SIZE);
return 0;
}
My understanding is that arrays are really just pointers
Let's get that out of the way. No, arrays are not pointers. Arrays are a series of objects, all of the same type, contiguous in memory.
Arrays can be passed by reference, but that is not what is usually done. What is usually done, which is what you are doing, is passing a pointer to the first element of the array. Arrays can and will "decay" to a pointer to their first element upon demand. And that's what is happening when you pass rates to show1 and show2.
Inside show1 and show2, list starts out as a pointer to rates[0]. You're free to modify this pointer to point at any other double.
If you wanted to pass an array by reference, it would look like this:
void show3(double (&list)[9]) { ... }
Or the more versatile:
template<size_t SIZE>
void show3(double (&list)[SIZE]) { ... }
Note that what you can't do is pass an array by value (unless it is contained within another object). If you write a function which looks like it is taking an array by value, e.g.
void show4(double list[9]) { ... }
It is actually a pointer, and that number 9 is meaningless. Native arrays suck.
First, arrays are converted to a pointer to the first element when passed as the function argument. BTW, arrays are not pointers, as one example, sizeof(rates) in your code isn't the size of a pointer.
Second, arrays are passed by value since you are not using references.
So in the function show2, you are modifying a pointer, which is fine.
Arrays are not pointers. C++ has inherited "Array-Pointer Equivalence" from C which means that a well-known array variable can decay to a pointer, primarily for the purpose of offset math and for avoiding passing arrays by value:
int array[64];
int* a = array; // equivalent to a = &array[0];
Array's aren't pointers. If you use an array variable name in a pointer context, it will "decay" to a pointer - that is, lose the extended attributes available from an array object.
int array[64];
int* a = array;
std::cout << "array size = " << sizeof(array) << "\n";
std::cout << "a size = " << sizeof(a) << "\n";
std::cout << "(int*)(array) size = " << sizeof((int*)array)) << "\n";
"Array size" will be 256 (int is 4 bytes, 64 of them = 256 bytes), "a size" will be 4 or 8 bytes depending on 32/64 bits, and "(int*)(array)" size will be the same size as the pointer.
People often think that arrays are passed by value. This is not true: http://ideone.com/hAeH18
#include <iostream>
void bump(int arr[3]) {
for (size_t i = 0; i < 3; ++i)
arr[i]++;
}
int main() {
int array[] = { 1, 2, 3 };
bump(array);
for (size_t i = 0; i < 3; ++i)
std::cout << array[i] << "\n";
return 0;
}
This outputs "2, 3, 4" not "1, 2, 3".
This occurs because arrays decay to pointers when passed as function arguments. But to support the syntax for receiving arrays as arrays, C has to be able to treat pointers like arrays in some contexts:
void f1(int* a) { a[0]++; }
void f2(int* a) { (*a)++; }
void f3(int a[]) { a[0]++; }
void f4(int a[]) { (*a)++; }
void f5(int a[1]) { a[0]++; }
void f6(int a[1]) { (*a)++; }
All of these functions produce the same code.
In C, this originated from the fact that array information is lost at compile time. So this function:
void f(int array[])
has no way to tell how large the array it is receiving is. They wanted programmers to be conscious of this and be careful about how/if they passed size information - e.g. in the case of char arrays, instead of size, we have the nul terminator byte.
Unfortunately they didn't choose to make it obvious by diasllowing the representation that makes it look like you are receiving an array with size information intact :(
What is the difference between:
void foo(item* list)
{
cout << list[xxx].string;
}
and
void this(item list[])
{
cout << list[xxx].string;
}
Assuming item is:
struct item
{
char* string;
}
With the pointer pointing to the first of an array of chars
and list is just an array of items...
To the compiler, there is no difference.
It reads different though. [] suggests you want to pass an array to the function, whereas * could also mean just a simple pointer.
Note that arrays decay to pointers when passed as parameters (in case you didn't already know).
They are the same - completely synonymous. And the second is item list[], not item[]list.
However it is customary to use [] when the parameter is used like an array and * when it's used like a pointer.
FYI:
void foo(int (&a)[5]) // only arrays of 5 int's are allowed
{
}
int main()
{
int arr[5];
foo(arr); // OK
int arr6[6];
foo(arr6); // compile error
}
but foo(int* arr), foo(int arr[]) and foo(int arr[100]) are all equivalent
When print_array is called, the size of the int array[] parameter (count) isn't what was expected. It seems sizeof is not returning the size of the entire array which would be 5*sizeof(int) = 20.
namespace Util
{
void print_array(int array[])
{
size_t count = (sizeof array)/(sizeof array[0]);
cout << count;
// int count = sizeof(array)/sizeof(array[0]);
// for (int i = 0; i <= count; i++) cout << array[i];
}
}
int array_test[5]={2,1,5,4,3};
Util::print_array(array_test);
int array[] here becomes int* array, and sizeof(array) returns the same thing sizeof(int*). You need to pass an array by reference to avoid that.
template <size_t N>
void print_array(int (&array)[N]) {
std::cout << N;
}
int array[] = { 2, 1, 5, 4, 3 };
print_array(array);
Read this: it says the way to fix this, but for a quick description:
When a function has a specific-size array parameter, why is it replaced with a pointer?
Using sizeof(array) will work in the scope that the array is statically defined in. When you pass it into a function though the type gets converted into a pointer to the array element type. In your case, when you're in print_array it is an int*. So, your sizeof in in the function will be the size of a pointer on your system (likely 32 or 64 bits).
You can get around this with some fancy syntax like so (from the link above):
If you want that the array type is preserved, you should pass in a
reference to the array:
void foo ( int(&array)[5] );
but I'd say just pass the size in as well as another parameter, its more readable.
As this array is implemented as a thin overlay on pointers, the variable you have is just a pointer, so sizeof will return the size of your pointer.
The only way to know the length of an array is to place a terminating object, as the null character in C strings.
There is no other way to determine the size of an array if you only have a pointer to it.
Here's a trick: you can take a reference to an array of fixed size. You can use this to template-deduce the size.
#include <iostream>
char a [22];
char b [33];
void foo (char *, size_t size)
{
std :: cout << size << "\n";
}
template <size_t N>
void foo (char (&x) [N])
{
foo (x, N);
}
int main () {
foo (a);
foo (b);
}
This prints 22\n33\n
void print_array( int array[] ) is synonymous with void print_array( int *array ). No size information is passed when the function call is made, so sizeof doesn't work here.
For an algorithm like this, I like to use iterators, then you can do what you want... e.g.
template <typename Iterator>
void print(Interator begin, Iterator end)
{
std::cout << "size: " << std::distance(begin, end) << std::endl;
std::copy(begin, end, std::ostream_iterator<std::iterator_traits<Iterator>::value_type>(std::cout, ", "));
}
to call
print(a, a + 5); // can calculate end using the sizeof() stuff...
just an addition to all the answers already posted:
if you want to use an array which is more comfortable (like an ArrayList in java for instance) then just use the stl-vector container which is also able to return its size
All the following declarations are exactly same:
void print_array(int array[]);
void print_array(int array[10]);
void print_array(int array[200]);
void print_array(int array[1000]);
void print_array(int *array);
That means, sizeof(array) would return the value of sizeof(int*), in all above cases, even in those where you use integers (they're ignored by the compiler, in fact).
However, all the following are different from each other, and co-exist in a program, at the same time:
void print_array(int (&array)[10]);
void print_array(int (&array)[200]);
void print_array(int (&array)[1000]);
int a[10], b[200], c[1000], d[999];
print_array(a); //ok - calls the first function
print_array(b); //ok - calls the second function
print_array(c); //ok - calls the third function
print_array(d); //error - no function accepts int array of size 999
If I change the type to const char str[Len], I get the following error:
error: no matching function for call to ‘static_strlen(const char [5])’
Am I correct that static_strlen expects an array of const char references? My understanding is that arrays are passed as pointers anyway, so what need is there for the elements to be references? Or is that interpretation completely off-the-mark?
#include <iostream>
template <size_t Len>
size_t
static_strlen(const char (&str)[Len])
{
return Len - 1;
}
int main() {
std::cout << static_strlen("oyez") << std::endl;
return 0;
}
No, the function parameter is a reference to an array of Len const chars. That's how the function knows the length (assuming the last byte is a NUL terminator, hence the -1). The parentheses are there precisely to stop it being what you think it is.
Actually there's no such thing in C++ as an array of references, so it couldn't be what you think it is even without the parens. I guess (but am not sure) that the need for the parens is just for consistency with other similar type definitions, such as pointers to arrays:
void fn(const char *a[3]); // parameter a is of type const char**, the 3 is ignored.
void fn(const char (*a)[3]; // parameter a is a pointer to an array of 3 const chars.
That example also illustrates why an array is not a pointer. Predict the output of the following program, and then run it:
#include <iostream>
void fn(const char (*a)[3]) {
std::cout << sizeof(a) << "\n" << sizeof(*a) << "\n";
}
void fn2(const char *a[3]) {
std::cout << sizeof(a) << "\n" << sizeof(*a) << "\n";
}
int main() {
const char a[3] = {};
const char **b = 0;
fn(&a);
fn2(b);
}
#if 0
// error: declaration of `a' as array of references
void fn3(const char & a[3]) {
std::cout << sizeof(a) << "\n" << sizeof(*a) << "\n";
}
#endif
This is one of the way that a function can be made such that the size of the array is passed into the function automatically.
static_strlen(const char (&str)[Len])
is a function that takes in an array of const char of exactly Len elements. The array size must be known at compile time. I.e. the array wasn't allocated via new or malloc.
To be more specific, the parameter is a reference to an array of Len elements, rather than an actual array, which is why it doesn't get converted into a pointer when passed.