- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- A Tour of C99
- C++0X: The New Face of Standard C++ New
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- Converting a String to Upper Case
- Calling Member Functions with an Invalid this
- Passing an Array to a Function
- Fast Object Initialization
- C++ Sudoko, or How to Become a Real Hacker
- Member Name Lookup
- An Operating Overloading Question
- Living Without New
- Solving a Mysterious Compilation Error
- A Magical printf() Call or a Buggy Mess?
- Submitting a Library to the Standards Committee
- The Portable Datatypes Dilemma
- Can I Assign Pointers to a Specific Memory Address?
- Header File Naming Issues
- The Linkage of Enumerations
- unique_ptr And The Deprecation Of auto_ptr
- A const Member Function Conundrum
- Bugzilla
- A Response to Linus Torvalds' C++ Diatribe
- Pseudo Constructor Initializers
- Comment Terminators and The Keyword int
- Questions About enum Types
- Pointers to volatile
- Warnings on const Declarations
- Questions About inline
- The Costs of Virtual Functions
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
Passing an Array to a Function
Last updated Jun 17, 2005.
In a previous column, I claimed that passing an array as a function argument was impossible. The problem is that the array is implicitly converted, or decays, into a pointer. The pointer, alas, doesn't store the array's dimension; it doesn't even tell you that the variable in question is an array. I recently received an e-mail message from a reader who proposed a technique for passing arrays as arguments without the implicit conversion to pointers. Here it is:
"I'm not sure you are correct when you say in your article that functions in C++ can't receive array arguments. I have written functions that take array arguments before. It only works for statically sized arrays, and the parameter has to specify the size of the array, but it is possible. The syntax is something like:
void foo(int (&array)[10]);which declares a function that takes an array of 10 integers. This does not seem useful at first, but by using template parameter deduction you can write generic functions that operate on statically sized arrays in this way:
template <typename T, size_t size> void foo(T (&array)[size]) { //sort array, find the sum, min, max, etc }Of course as you say in your article, you have to be careful that the array does not decay to a pointer as you are passing it around. In this case though, the code should simply not compile since the template will not match."
Before I go on, let's parse the following function declaration, which might look a bit cryptic:
void foo(int (&array)[10]);
What's interesting here is how the parameter is declared: int (&array)[10] is a reference to an array of 10 ints. So, what gets passed on the callee's stack is actually a reference, not a real array; though, for most practical purposes, there is no difference between the two. (For a review of the three argument passing mechanisms of C++, see this section.)
Unlike passing an array by value, which causes the array to decay into a bare pointer, the use of a reference to a statically-allocated array is seemingly safer, because the callee has access to the type information associated with the array. Particularly, a sizeof() expression returns the correct array size even when used inside the callee:
void foo(int (&arr)[10])
{
cout<<sizeof(arr)<<endl; //output: 40
}
int main()
{
int arr[10];
foo(arr);
}
When you use a reference to a statically sized array, the compiler is also capable of detecting type mismatches at the place of all:
int arr[5]; //wrong dimension foo(arr); //compiler diagnostic
There are a few caveats here, though. The main problem is that a reference to an array is a slippery type -- you can inadvertently convert it to a bare pointer, thus losing important type information. Consider the following example:
void func(int* p) {}
void foo(int (&arr)[10])
{
func(arr);
}
When func() is called, the argument arr decays into a pointer. Remember: once an array has decayed into a pointer, the array's type information is lost. This isn't the only problem that might arise, though. Consider the following typeid() expression. I expected it to produce a complete description of the array's type, including its dimension:
void foo(int (&arry)[10])
{
cout<<typeid(arry).name()<<endl;
}
However, the cout expression reports "int *". We can conclude that there are limits as to how far you can push this technique. If it isn't used in generic functions that operate on statically sized arrays, I still recommend the array_wrapper class template presented in the original column as it offers a safer and efficient alternative.


Account Sign In
View your cart