简体   繁体   中英

Passing an array as a function parameter in C++

In C++, arrays cannot be passed simply as parameters. Meaning if I create a function like so:

void doSomething(char charArray[])
{
    // if I want the array size
    int size = sizeof(charArray);
    // NO GOOD, will always get 4 (as in 4 bytes in the pointer)
}

I have no way of knowing how big the array is, since I have only a pointer to the array.

Which way do I have, without changing the method signature, to get the size of the array and iterate over it's data?


EDIT: just an addition regarding the solution. If the char array, specifically, was initialized like so:

char charArray[] = "i am a string";

then the \\0 is already appended to the end of the array. In this case the answer (marked as accepted) works out of the box, so to speak.

Use templates. This technically doesn't fit your criteria, because it changes the signature, but calling code does not need to be modified.

void doSomething(char charArray[], size_t size)
{
   // do stuff here
}

template<size_t N>
inline void doSomething(char (&charArray)[N])
{
    doSomething(charArray, N);
}

This technique is used by Microsoft's Secure CRT functions and by STLSoft's array_proxy class template.

Without changing the signature? Append a sentinel element. For char arrays specifically, it could be the null-terminating '\\0' which is used for standard C strings.

void doSomething(char charArray[])
{
    char* p = charArray;
    for (; *p != '\0'; ++p)
    {
         // if '\0' happens to be valid data for your app, 
         // then you can (maybe) use some other value as
         // sentinel
    }
    int arraySize = p - charArray;

    // now we know the array size, so we can do some thing
}

Of course, then your array itself cannot contain the sentinel element as content. For other kinds of (ie, non-char) arrays, it could be any value which is not legal data. If no such value exists, then this method does not work.

Moreover, this requires co-operation on the caller side. You really have to make sure that the caller reserves an array of arraySize + 1 elements, and always sets the sentinel element.

However, if you really cannot change the signature, your options are rather limited.

It actually used to be a quite common solution to pass the length in the first element of the array. This kind of structure is often called BSTR (for “BASIC string”), even though this also denoted different (but similar) types.

The advantage over the accepted solution is that determining the length using a sentinel is slow for large strings. The disadvantage is obviously that this is a rather low-level hack that respects neither types nor structure.

In the form given below it also only works for strings of length <= 255. However, this can easily be expanded by storing the length in more than one byte.

void doSomething(char* charArray)
{
    // Cast unnecessary but I prefer explicit type conversions.
    std::size_t length = static_cast<std::size_t>(static_cast<unsigned char>(charArray[0]));
    // … do something.
}

In general when working with C or low-level C++, you might consider retraining your brain to never consider writing array parameters to a function, because the C compiler will always treat them as pointers anyway. In essence, by typing those square brackets you are fooling yourself in thinking that a real array is being passed, complete with size information. In reality, in C you can only pass pointers. The function

void foo(char a[])
{
    // Do something...
}

is, from the point of view of the C compiler, exactly equivalent to:

void foo(char * a)
{
    // Do something
}

and obviously that nekkid char pointer contains no length information.

If you're stuck in a corner and can't change the function signature, consider using a length prefix as suggested above. A non-portable but compatible hack is to specify the array length in an size_t field located before the array, something like this:

void foo(char * a)
{
    int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
    int c_len = ((size_t *)a)[-1];
}

Obviously your caller needs to create the arrays in the appropriate way before passing them to foo.

Needless to say this is a horrible hack, but this trick can get out of trouble in a pinch.

如果它是无效的,strlen()将起作用。

You can't determine the size from charArray alone. That information is not automatically passed to the function.

Of course if it's a null-terminated string you can use strlen() , but you have probably considered that already!

Consider passing a std::vector<char> & parameter, or a pair of pointers, or a pointer plus a size parameter.

This is actually more C than C++, in C++ you'd probably rather use a std::vector. However, in C there's no way to know the size of an array. The compile will allow you to do a sizeof if the array was declared in the current scope, and only if it was explicitly declared with a size ( and "with a size", I mean that it was either declared with an integer size or initialized at declaration, as opposed to being passed as a parameter, thanks for the downvote). 和“with a size”,我的意思是它是用整数大小声明的)或者在声明时初始化,而不是作为参数传递,感谢downvote)。

The common solution in C is to pass a second parameter describing the number of elements in the array.


Sorry, missed the part about not wanting to change the method signature. Then there's no solution except as described by others as well, if there's some data that is not allowed within the array, it can be used as a terminator (0 in C-strings, -1 is also fairly common, but it depends on your actual data-type, assuming the char array is hypothetical)

In order for a function to know the number of items in an array that has been passed to it, you must do one of two things:

  1. Pass in a size parameter
  2. Put the size information in the array somehow.

You can do the latter in a few ways:

  • Terminate it with a NULL or some other sentinel that won't occur in normal data.
  • store the item count in the first entry if the array holds numbers
  • store a pointer to the last entry if the array contains pointers

try using strlen(charArray); using the cstring header file. this will produce the number of characters including spaces till it reaches the closing ".

You are guarranteed to receive 4 in a 32-bit PC and that's the correct answer. because of the reason explained here and here . The short answer is, you are actually testing the sizeof a pointer rather than an array, because "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."

Now that you are using C++, boost::array is a better choice than raw arrays. Because it's an object, you won't loose the dimention info now.

I think you can do this:

size_t size = sizeof(array)/sizeof(array[0]);

PS: I think that the title of this topic isn't correct, too.

Dude you can have a global variable to store the size of the array which will be accessible throughout the program. At least you can pass the size of the array from the main() function to the global variable and you will not even have to change the method signature as the size will be available globally.

Please see example:

#include<...>
using namespace std;

int size; //global variable

//your code

void doSomething(char charArray[])
{
    //size available

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM