2009-01-14 228 views
16

在C++中,数组不能简单地作为参数传递。在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 charArray[] = "i am a string"; 

\0已经附加到该阵列的端部。在这种情况下,答案(标记为接受)可以开箱即用,可以这么说。

+2

实际上这里有一个相当大的误解,你的例子中的语法没有任何意义:函数在栈上获取未知数量的数据。忽略你原来的语法,并给函数签名`void doSomething(char * charArray)`。如果你用char数组[10]; doSomething(array) //c-faq.com/aryptr/aryptrparam.html – kfsone 2013-06-02 17:53:24

回答

22

不改变签名?追加一个哨兵元素。特别是对于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元素。

但是,如果您确实无法更改签名,您的选择就会受到限制。

+0

代码示例好吗?:) – 2009-01-14 21:26:17

+0

是的,我还在打字:) – Reunanen 2009-01-14 21:29:49

+0

非常好的解决方案,像一个魅力工作。谢谢! – 2009-01-14 21:47:36

4

如果它是nullterminated,strlen()将工作。

+1

是的,这是问题中char数组的完美答案,但不适用于其他数据类型。 – Reunanen 2009-01-14 21:35:54

+0

除了写`doSomething(NULL);`完全合法的事实。 **编译器**将OP指纹更改为`char * charArray` :) http://c-faq.com/aryptr/aryptrparam.html – kfsone 2013-06-02 18:01:23

2

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

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

考虑传递一个参数或一对指针或一个指针加上一个大小参数的一个参数std::vector<char>

+0

我认为Yuval对函数签名的限制。 – Calyth 2009-01-14 21:45:56

+0

@finnw这是因为它根本不传递数组,它只是传递一个指针。 – kfsone 2013-06-02 18:00:42

2

这实际上比C++更C,在C++中你可能更愿意使用std :: vector。但是,在C中无法知道数组的大小。如果数组是在当前范围内声明的,并且仅当它被显式声明为一个大小(编辑:和“与一个大小”,我的意思是它或者声明为一个大小整数大小或声明时初始化,而不是作为参数传递,感谢downvote)。

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

编辑:
对不起,错过了有关不想更改方法签名的部分。那么除了别人所描述的解决方案之外,没有任何解决方案,如果有一些数据在数组中是不允许的,那么它可以用作终止符(0在C字符串中,-1也是相当常见的,但它取决于您的实际的数据类型,假设字符数组是假设)

1

为了了解在已传递给它一个数组的项数的函数,你必须做两件事情之一:

  1. 传递大小参数
  2. 将大小信息以某种方式放入数组中。

你可以做后者在几个方面:

  • 用NULL或不会在 正常数据出现一些 其他定点终止它。
  • 店的项目中的第一项算,如果数组包含数字
  • 存放指向最后一个条目,如果数组包含指针
35

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

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

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

这种技术是由微软的Secure CRT functions和STLSoft的array_proxy类模板使用。

5

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

优于公认的解决方案的优点是,使用标记确定长度对于大型字符串来说很慢。缺点是显然这是一种既不尊重类型,也不尊重结构的低级别攻击。

在下面给出的格式中,它也只适用于长度为< = 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. 
} 
5

一般用C或低级别的C工作++时,你可能会考虑再培训你的大脑从来没有考虑写阵列参数的函数,因为C编译器总是把他们当作指针反正。从本质上讲,通过输入那些方括号,你就会想到真正的数组正在被传递,并附有大小信息。实际上,在C中你只能通过指针。功能

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

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

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

并且显然该nekkid字符指针不包含长度信息。

如果你被困在一个角落,并且不能改变函数签名,可以考虑使用上面建议的长度前缀。非便携式但兼容的黑客是指定数组长度位于size_t型场前阵,这样的事情:

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

显然你的调用者需要通过他们之前在适当的方式来创建数组去富。

毋庸置疑,这是一个可怕的黑客攻击,但这个伎俩可以摆脱困境在一个捏。

-1

您可以保证在32位个人电脑中收到4个,这是正确的答案。因为解释herehere的原因。 简单的回答是,你实际上正在测试一个指针的大小而不是一个数组,因为“该数组被隐式地转换或衰减为一个指针,指针,唉,不存储数组的维度;它不会'你甚至可以告诉你所讨论的变量是一个数组。“

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

-2

我认为你可以这样做:

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

PS:我认为这个专题的标题是不正确的,太。

-3

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

请看例子:

#include<...> 
using namespace std; 

int size; //global variable 

//your code 

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

} 
0

尝试使用的strlen(charArray);使用cstring头文件的 。这将产生包括空格在内的字符数量直到达到结尾“

相关问题