简体   繁体   English

在C ++中将数组作为函数参数传递

[英]Passing an array as a function parameter in C++

In C++, arrays cannot be passed simply as parameters. 在C ++中,数组不能简单地作为参数传递。 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数组,特别是初始化如下:

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

then the \\0 is already appended to the end of the array. 然后\\0已经附加到数组的末尾。 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. Microsoft的Secure CRT函数和STLSoft的array_proxy类模板使用此技术。

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. 具体来说,对于char数组,它可以是用于标准C字符串的空终止'\\0'

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. 当然,那么你的数组本身不能包含sentinel元素作为内容。 For other kinds of (ie, non-char) arrays, it could be any value which is not legal data. 对于其他类型(即非char)数组,它可以是任何非合法数据的值。 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. 你必须确保调用者保留一个arraySize + 1元素数组,并始终设置sentinel元素。

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. 这种结构通常称为BSTR (用于“BASIC字符串”),即使这也表示不同(但相似)的类型。

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. 在下面给出的形式中,它也仅适用于长度<= 255的字符串。但是,通过将长度存储在多个字节中,可以很容易地扩展它。

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. 通常,在使用C或低级C ++时,您可能会考虑重新训练大脑,从不考虑将数组参数写入函数,因为C编译器总是将它们视为指针。 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. 实际上,在C中你只能传递指针。 The function 功能

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

is, from the point of view of the C compiler, exactly equivalent to: 从C编译器的角度来看,它完全等同于:

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

and obviously that nekkid char pointer contains no length information. 显然,nekkid char指针不包含长度信息。

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: 一个不可移植但兼容的hack是在数组之前的size_t字段中指定数组长度,如下所示:

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. 显然,调用者需要在将数组传递给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. 您无法单独使用charArray确定大小。 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! 当然,如果它是一个以null结尾的字符串,你可以使用strlen() ,但你可能已经考虑过了!

Consider passing a std::vector<char> & parameter, or a pair of pointers, or a pointer plus a size parameter. 考虑传递一个std::vector<char> &参数,或一对指针,或指针加上一个size参数。

This is actually more C than C++, in C++ you'd probably rather use a std::vector. 这实际上比C ++更多C,在C ++中你可能更喜欢使用std :: vector。 However, in C there's no way to know the size of an array. 但是,在C中,无法知道数组的大小。 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 ( EDIT: 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). 如果数组是在当前作用域中声明的,编译将允许你执行sizeof,并且只有在使用大小显式声明它时( EDIT:和“with a size”,我的意思是它是用整数大小声明的)或者在声明时初始化,而不是作为参数传递,感谢downvote)。

The common solution in C is to pass a second parameter describing the number of elements in the array. C中的常见解决方案是传递描述数组中元素数量的第二个参数。

EDIT: 编辑:
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) 然后除了其他人所描述的之外没有解决方案,如果在数组中有一些不允许的数据,它可以用作终结符(C字符串中的0,-1也很常见,但它取决于你的实际的数据类型,假设char数组是假设的)

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. 使用NULL或其他一些不会出现在普通数据中的标记来终止它。
  • 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); 尝试使用strlen(charArray); using the cstring header file. 使用cstring头文件。 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. 您有责任在32位PC中接收4,这是正确的答案。 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. 现在您正在使用C ++, boost :: array是比原始数组更好的选择。 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. PS:我认为这个话题的标题也不正确。

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. 至少你可以将数组的大小从main()函数传递给全局变量,你甚至不必更改方法签名,因为大小可以全局使用。

Please see example: 请看例子:

#include<...>
using namespace std;

int size; //global variable

//your code

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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