翻译《有关编程、重构及其他的终极问题?》——31.在C-C++中数组不是值传递的
2017-08-14 15:29
369 查看
翻译《有关编程、重构及其他的终极问题?》——31.在C/C++中数组不是值传递的
标签(空格分隔):翻译 技术 C/C++作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年08月14日
31.在C/C++中数组不是值传递的
下面这段代码摘自Wolf游戏项目。PVS-Studio分析器对这段代码的诊断结果为:V511 The sizeof() operator returns size of the pointer, and not of the array, in ‘sizeof (src)’ expression(译者注:sizeof()操作符返回的是指针的尺寸大小,而不是数组的)。ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy( mat, src, sizeof( src ) ); }
解释
有时候,程序员们忘记了C/C++不可以通过值传递给函数传递数组,这是因为实际上把数组的指针作为一个参数传递了。数组后面方括号的数字其实没有意义,它们仅仅可以作为对程序员的提示,所以一般我们会把数组尺寸作为另外一个参数进行传递。事实上,你可以传递一个完全不同的尺寸,比如,下面的代码将会成功编译:
void F(int p[10]) { } void G() { int p[3]; F(p); }
对应的,sizeof(src)操作符计算的也不是数组的尺寸,而是指针的尺寸。结果,memcpy()将只拷贝数组中的部分数据。也就是说,4或者8字节,这依赖于指针的长度大小(没有考虑一些不常见的架构)。
正确的代码
最简单的纠正代码的方式可以如下:
ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy(mat, src, sizeof(float) * 3 * 3); }
建议
有几个方法可以让你的代码更安全。
如果数组大小已知:你可以让函数使用数组的引用。但不是每个人知道可以这么做,并且知道怎么写个的人就更少了。所以我希望这个例子将会有趣和有用的:
ID_INLINE mat3_t::mat3_t( float (&src)[3][1] ) { memcpy( mat, src, sizeof( src ) ); }
现在,就有可能给一个函数传递正确大小的数组了。并且最重要的,sizeof()操作符将会计算数组的尺寸,而不是指针的。
还有另外一个解决这个问题的方式就是开始使用std:array类。
如果数组大小未知:一些编程书籍的作者建议使用std::vector类,以及其他类似的类,但实际来说这并不方便。
有时候你使用一个简单的指针,你应该传递两个参数给函数:一个指针和这个指针所指向元素的个数。然后,总体而言,这是不是好的实践,因为会导致很多bug。
类似这些例子,你可以在《C++核心编程向导》中找到一些有用且值得一读的思路。我还建议读读《不要把一个数组当成一个指针传递》这篇文章。当你有任何空闲时间时,应该首先读读《C++核心编程向导》,里面包含了很多有用的主意。
相关文章推荐
- 翻译《有关编程、重构及其他的终极问题?》——28.如果你可以使用简单的函数就不要使用宏
- 翻译《有关编程、重构及其他的终极问题?》——4.小心--操作符,请把表达式放在括号中
- 翻译《有关编程、重构及其他的终极问题?》——2.比0大的并不意味着就只是1
- 翻译《有关编程、重构及其他的终极问题?》——8.记住:析构函数中的异常是危险的
- 翻译《有关编程、重构及其他的终极问题?》——26.潜伏的VARIANT_BOOL
- 翻译《有关编程、重构及其他的终极问题?》——23.自动获取字符串的长度
- 翻译《有关编程、重构及其他的终极问题?》——12.当使用拷贝黏贴,一定要特别注意最后一行
- 翻译《有关编程、重构及其他的终极问题?》——16.在编程过程中“装逼”是不可接受的
- 翻译《有关编程、重构及其他的终极问题?》——6.当把一个指针明确的转换为整型时,请检查所有相关代码
- 翻译《有关编程、重构及其他的终极问题?》——19.如何合理的从一个构造函数中调用另外一个构造函数
- 翻译《有关编程、重构及其他的终极问题?》——17.使用专门的函数清除专有数据
- 翻译《有关编程、重构及其他的终极问题?》——22.不要使用#pragram warning(default-X)
- 翻译《有关编程、重构及其他的终极问题?》——13.表格化的格式化
- 翻译《有关编程、重构及其他的终极问题?》——9.使用'-0'符号作为结尾标记
- 翻译《有关编程、重构及其他的终极问题?》——21.正确的检查文件的结尾符(EOF)
- 翻译《有关编程、重构及其他的终极问题?》——1. 别把编译器的事给做了
- 翻译《有关编程、重构及其他的终极问题?》——14.一个好的编译器和代码风格还不够
- 翻译《有关编程、重构及其他的终极问题?》——20.光对文件做EOF检查可能还不够
- 翻译《有关编程、重构及其他的终极问题?》——10.避免使用多个小的#ifdef块
- 翻译《有关编程、重构及其他的终极问题?》——27.狡猾的BSTR字符串