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

时间:2009-01-14 21:24:11

标签: c++ arrays pointers parameters 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)
}

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

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


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

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

然后\0已经附加到数组的末尾。在这种情况下,答案(标记为已接受)可以直接使用,可以这么说。

12 个答案:

答案 0 :(得分:38)

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

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

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

此技术由Microsoft的Secure CRT functions和STLSoft的array_proxy类模板使用。

答案 1 :(得分:23)

不改变签名?附加一个哨兵元素。具体来说,对于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
}

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

此外,这需要呼叫方的合作。你必须确保调用者保留一组arraySize + 1个元素,总是设置sentinel元素。

但是,如果你真的无法改变签名,那么你的选择相当有限。

答案 2 :(得分:6)

它实际上曾经是一个非常常见的解决方案,用于传递数组第一个元素的长度。这种结构通常称为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.
}

答案 3 :(得分:6)

通常在使用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<std::size_t *>(a)[-1];
    int c_len = ((size_t *)a)[-1];
}

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

毋庸置疑,这是一个可怕的黑客,但这个技巧可以在紧要关头摆脱困境。

答案 4 :(得分:4)

如果它是null终止的,strlen()会起作用。

答案 5 :(得分:2)

您无法单独从charArray确定尺寸。该信息不会自动传递给函数。

当然如果它是一个以空字符结尾的字符串,你可以使用strlen(),但你可能已经考虑过了!

考虑传递std::vector<char>&amp;参数,或一对指针,或指针加上大小参数。

答案 6 :(得分:2)

这实际上比C ++更多C,在C ++中你可能更喜欢使用std :: vector。但是,在C中,无法知道数组的大小。编译将允许你在当前作用域中声明数组时执行sizeof,并且只有在使用大小(编辑:和“具有大小”)显式声明它时,我的意思是它要么声明为整数大小,要么在声明时初始化,而不是作为参数传递,感谢downvote)。

C中的常见解决方案是传递第二个参数,描述数组中元素的数量。

修改:
对不起,错过了关于不想更改方法签名的部分。然后除了其他人所描述的之外没有解决方案,如果在数组中有一些不允许的数据,它可以用作终结符(C字符串中的0,-1也很常见,但它取决于你的实际数据类型,假设char数组是假设的)

答案 7 :(得分:1)

为了让函数知道已传递给它的数组中的项数,您必须执行以下两项操作之一:

  1. 传入尺寸参数
  2. 以某种方式将大小信息放入数组中。
  3. 您可以通过以下几种方式完成后者:

    • 使用NULL或其他方式终止它 其他不会发生的哨兵 正常数据。
    • 如果数组包含数字
    • ,则将项目计数存储在第一个条目中
    • 如果数组包含指针
    • ,则存储指向最后一个条目的指针

答案 8 :(得分:0)

尝试使用strlen(charArray); 使用cstring头文件。这将产生包括空格的字符数,直到它到达结束时。

答案 9 :(得分:-1)

您有责任在32位PC上接收4,这是正确的答案。因为解释herehere的原因。 简短的回答是,你实际上测试的是指针而不是数组的大小,因为“数组被隐式转换或衰减成指针。指针,唉,不存储数组的维度;它不是甚至告诉你,有问题的变量是一个数组。“

现在您正在使用C ++,boost::array是比原始数组更好的选择。因为它是一个对象,你现在不会丢失维度信息。

答案 10 :(得分:-2)

我认为你可以这样做:

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

PS:我认为这个主题的标题也不正确。

答案 11 :(得分:-3)

Dude你可以有一个全局变量来存储整个程序可以访问的数组大小。至少你可以将数组的大小从main()函数传递给全局变量,你甚至不必更改方法签名,因为大小将在全局范围内可用。

请参阅示例:

#include<...>
using namespace std;

int size; //global variable

//your code

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

}