标题:能否只传递数组a作为函数参数而在函数中得到数组a的长度
只看楼主
牧人马
Rank: 4
等 级:业余侠客
威 望:6
帖 子:49
专家分:229
注 册:2017-12-24
结帖率:33.33%
已结贴  问题点数:20 回复次数:5 
能否只传递数组a作为函数参数而在函数中得到数组a的长度
rt,附上以下代码
发现函数中的sizeof(a)/sizeof(a[0])不等于main函数中的值后,我在网上查阅到这是因为当数组名作为函数参数传递后,“退化”为指针,sizeof自然也就不能得到数组的长度,只是得到一个指针的长度而已。那么能否在不传递数组a的长度作为参数的前提下,在函数中得到数组a的长度呢,或者说能否避免当数组名作为函数参数传递后退化为指针的问题?
程序代码:
#include <iostream>
using namespace std;
void tot(int a[])
{
    cout << " this is tot , sizeof(a)/sizeof(a[0])= " << sizeof(a) / sizeof(a[0]) << " sizeof(a)=" << sizeof(a) << endl;
    for (int i=0;i<10;i++)
        cout << " " << a[i];
}

int main()
{
    int a[] = { 1,3,5,7,9,11,13,15,17,19 };
    cout << "this is main , sizeof(a)/sizeof(a[0])= " << sizeof(a) / sizeof(a[0]) << " sizeof(a)=" << sizeof(a) << endl;
    tot(a);

}
搜索更多相关主题的帖子: sizeof 长度 数组 传递 函数 
2020-06-28 01:20
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:20 
首先,void tot( int a[] ) 这种形式,传递的是指针,不是数组。(平时说“传递数组”无所谓,但在这个话题下,需要严格区分)
传递数组也是可以的,例如 void tot( int (&a)[10] )。
假如你就是要传递一个 int[10] 作参数,那么 void tot( int (&a)[10] ) 是完美的。
然而很多时候,可能既要传递 int[10],也要传递 int[9]、int[123] 等等。
可是 int[10]、int[9]、int[123] 等是不同的类型,没法使用同一个函数申明,所以普通的函数是没有任何办法了。
可以使用 函数模板,函数模板 不是 函数,函数模板 是能生成函数的模板。例如
程序代码:
#include <iostream>
using namespace std;

template<size_t N> void tot( int (&a)[N] )
{
    cout << sizeof(a)/sizeof(a[0]) << '\n';
    cout << std::size(a) << '\n'; // 更建议使用这种简洁的模板函数
}

int main( void )
{
    int a[] = { 1,3,5,7,9,11,13,15,17,19 };
    tot(a);
    
    int b[] = { 1,2,3 };
    tot(b);
}

template<size_t N> void tot( int (&a)[N] ) 这个函数因为被 tot(a) 和 tot(b) 调用,所以它实际生成了两个函数,分别是 void tot( int (&a)[10] ) 和 void tot( int (&a)[3] )。

从上面可以看出,几种不同的参数调用就生成几种不同的函数重载。
假如你的 tot 函数实现就是如此简单,那么到此可以结束。
可是,如果tot本身实现很复杂,有100行代码,又被100种参数调用了,那么100行的代码就被复制了100份,严重浪费的代码膨胀。
这时候,可以只用 函数模板 传递数组长度,其本身不包含任何实现。例如
程序代码:
#include <iostream>
using namespace std;

static void tot_( int a[], size_t n )
{
    cout << n << '\n';
}

template<size_t N> void tot( int (&a)[N] )
{
    tot_( a, N );
}

int main( void )
{
    int a[] = { 1,3,5,7,9,11,13,15,17,19 };
    tot(a);
    
    int b[] = { 1,2,3 };
    tot(b);
}
2020-06-28 09:12
牧人马
Rank: 4
等 级:业余侠客
威 望:6
帖 子:49
专家分:229
注 册:2017-12-24
得分:0 
原程序是要先对递增的数组折半查找元素X后对结果进行操作,如果查找到X就与X的后继元素交换位置,没有查找到结果就按增序插入X不改变其他元素的顺序。所以想要在函数中能够得到数组的长度方便操作。
之前在学习C++时有学过函数模板,但是没有真正编程体会过它的实际作用所以一直忽视了这块,现在认识到了,多做补习,十分感谢!
2020-06-28 10:07
牧人马
Rank: 4
等 级:业余侠客
威 望:6
帖 子:49
专家分:229
注 册:2017-12-24
得分:0 
回复 2楼 rjsp
你好,我学疏才浅,还想冒昧的追问一些关于代码的知识
template<size_t N> void tot( int (&a)[N] )
{
    cout << sizeof(a)/sizeof(a[0]) << '\n';
    cout << std::size(a) << '\n'; // 更建议使用这种简洁的模板函数
}

查的资料里都是template <typename N>,声明是模板声明,告诉编译器N是一个泛型
但是我在编译器中把template<size_t N>中size_t 改为typename后会在int (&a)[N]处的N出现错误:不允许使用类型名
我的理解(猜测)是size_t并不是用于声明泛型的typename,N也不是泛型,那么size_t和N是什么类型,int (&a)[N]中的N是怎么获取到数组a中的大小的呢?
平日里几乎只用C++的语法和STL等做oj而没有实际应用过函数模板,重载,类的封装和继承等等,学的知识忘得干干净净,希望可以包涵
2020-06-29 01:12
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
模板形参 可以是 类型形参、非类型形参、模板形参。
详见 https://zh.

size_t 是个整型类型,与 int、long、intptr_t 等等同类
详见 https://zh.

假如你只是想传引用给tot,不管它是不是数组,那么可以这样
template<typename T> void tot( T& a )

假如你想传数组的引用给tot,非数组不被允许,那么可以这样
template<typename T, size_t N> void tot( T (&a)[N] )

假如你想传double数组的引用给tot,其它类型的数组不被允许,那么可以这样
template<size_t N> void tot( double (&a)[N] )

假如你想传长度为5的数组的引用给tot,是什么类型的数组无所谓,那么可以这样
template<typename T> void tot( T (&a)[5] )
收到的鲜花
  • 牧人马2020-06-29 12:56 送鲜花  1朵  
2020-06-29 10:28
牧人马
Rank: 4
等 级:业余侠客
威 望:6
帖 子:49
专家分:229
注 册:2017-12-24
得分:0 
回复 5楼 rjsp
十分感谢,这下清楚了,第一个链接的内容看的有些一知半解,看来还是要打好基本功
2020-06-29 12:54



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-502304-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020901 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved