当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在C++中将数组作为函数参数传递》经验,为你挑选了4个好方法。

在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)
}

我无法知道数组有多大,因为我只有一个指向数组的指针.

在不更改方法签名的情况下,我可以通过哪种方式获取数组的大小并迭代它的数据?


编辑:只是关于解决方案的补充.如果char数组,特别是初始化如下:

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

那么\0已经附加到数组的末尾.在这种情况下,答案(标记为已接受)可以开箱即用.



1> Josh Kelley..:

使用模板.这在技术上不符合您的标准,因为它会更改签名,但不需要修改调用代码.

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

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

Microsoft的Secure CRT函数和STLSoft的array_proxy类模板使用此技术.



2> Reunanen..:

没有改变签名?附加一个哨兵元素.特别是对于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
}

当然,那么你的数组本身不能包含sentinel元素作为内容.对于其他类型(即非char)数组,它可以是任何非合法数据的值.如果不存在此值,则此方法不起作用.

而且,这需要在呼叫者方面进行合作.你必须确保调用者保留一个arraySize + 1元素数组,并始终设置sentinel元素.

但是,如果您真的无法更改签名,则您的选项相当有限.



3> Konrad Rudol..:

它实际上曾经是一个非常常见的解决方案,用于传递数组第一个元素的长度.这种结构通常被称为BSTR(对于"BASIC字符串"),即使这也表示不同(但相似)的类型.

与已接受的解决方案相比,优点是使用标记确定长度对于大字符串来说是慢的.显而易见的是,这是一个相当低级别的黑客攻击,既不考虑类型也不考虑结构.

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

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


它有一个小问题'奇怪的C++和C处理char的原因.如果它已签名,则值> 127可能会在转换为size_t时导致巨大的size_t值(环绕).您可以通过首先转换为unsigned char来修复它:static_cast ((unsigned char)charArray [0]);

4> John Källén..:

通常,在使用C或低级C++时,您可能会考虑重新训练大脑,从不考虑将数组参数写入函数,因为C编译器总是将它们视为指针.从本质上讲,通过键入这些方括号,你自欺欺人地认为正在传递一个真正的数组,完成大小信息.实际上,在C中你只能传递指针.功能

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

从C编译器的角度来看,它完全等同于:

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

显然,nekkid char指针不包含长度信息.

如果您陷入困境且无法更改功能签名,请考虑使用上面建议的长度前缀.一个不可移植但兼容的hack是在数组之前的size_t字段中指定数组长度,如下所示:

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

显然,调用者需要在将数组传递给foo之前以适当的方式创建数组.

不用说这是一个可怕的黑客攻击,但这个技巧可以在紧要关头摆脱困境.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有