Yuv*_*dam 18 c++ arrays parameters pointers arguments
在C++中,数组不能简单地作为参数传递.这意味着如果我创建一个这样的函数:
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)
}
Run Code Online (Sandbox Code Playgroud)
我无法知道数组有多大,因为我只有一个指向数组的指针.
在不更改方法签名的情况下,我可以通过哪种方式获取数组的大小并迭代它的数据?
编辑:只是关于解决方案的补充.如果char数组,特别是初始化如下:
char charArray[] = "i am a string";
Run Code Online (Sandbox Code Playgroud)
那么\0已经附加到数组的末尾.在这种情况下,答案(标记为已接受)可以开箱即用.
Jos*_*ley 38
使用模板.这在技术上不符合您的标准,因为它会更改签名,但不需要修改调用代码.
void doSomething(char charArray[], size_t size)
{
// do stuff here
}
template<size_t N>
inline void doSomething(char (&charArray)[N])
{
doSomething(charArray, N);
}
Run Code Online (Sandbox Code Playgroud)
Microsoft的Secure CRT函数和STLSoft的array_proxy类模板使用此技术.
Reu*_*nen 24
没有改变签名?附加一个哨兵元素.特别是对于char数组,它可以'\0'是用于标准C字符串的空终止.
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
}
Run Code Online (Sandbox Code Playgroud)
当然,那么你的数组本身不能包含sentinel元素作为内容.对于其他类型(即非char)数组,它可以是任何非合法数据的值.如果不存在此值,则此方法不起作用.
而且,这需要在呼叫者方面进行合作.你必须确保调用者保留一个arraySize + 1元素数组,并始终设置sentinel元素.
但是,如果您真的无法更改签名,则您的选项相当有限.
它实际上曾经是一个非常常见的解决方案,用于传递数组第一个元素的长度.这种结构通常被称为BSTR(对于"BASIC字符串"),即使这也表示不同(但相似)的类型.
与已接受的解决方案相比,优点是使用标记确定长度对于大字符串来说是慢的.显而易见的是,这是一个相当低级别的黑客攻击,既不考虑类型也不考虑结构.
在下面给出的形式中,它也仅适用于长度<= 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.
}
Run Code Online (Sandbox Code Playgroud)
通常,在使用C或低级C++时,您可能会考虑重新训练大脑,从不考虑将数组参数写入函数,因为C编译器总是将它们视为指针.从本质上讲,通过键入这些方括号,你自欺欺人地认为正在传递一个真正的数组,完成大小信息.实际上,在C中你只能传递指针.功能
void foo(char a[])
{
// Do something...
}
Run Code Online (Sandbox Code Playgroud)
从C编译器的角度来看,它完全等同于:
void foo(char * a)
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
显然,nekkid char指针不包含长度信息.
如果您陷入困境且无法更改功能签名,请考虑使用上面建议的长度前缀.一个不可移植但兼容的hack是在数组之前的size_t字段中指定数组长度,如下所示:
void foo(char * a)
{
int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
int c_len = ((size_t *)a)[-1];
}
Run Code Online (Sandbox Code Playgroud)
显然,调用者需要在将数组传递给foo之前以适当的方式创建数组.
不用说这是一个可怕的黑客攻击,但这个技巧可以在紧要关头摆脱困境.