Loc*_*ead 45 c++ arrays function
有些语言只能声明一个函数返回一个像普通函数一样的数组,比如Java:
public String[] funcarray() {
String[] test = new String[]{"hi", "hello"};
return test;
}
Run Code Online (Sandbox Code Playgroud)
为什么C++不支持这样的东西int[] funcarray(){}?你可以返回一个数组,但是制作这样一个函数真的很麻烦.而且,我听说字符串只是char的数组.所以如果你能用C++返回一个字符串,为什么不用数组?
Dou*_*hen 61
我猜想要简明扼要,这只是一个设计决定.更具体地说,如果你真的想知道原因,你需要从头开始工作.
让我们先考虑一下C.在C语言中,"按引用传递"和"按值传递"之间存在明显的区别.为了轻视它,C中数组的名称实际上只是一个指针.对于所有意图和目的,差异(通常)归结为分配.代码
int array[n];
Run Code Online (Sandbox Code Playgroud)
将在堆栈上创建4*n字节的内存(在32位系统上),与任何代码块进行声明的范围相关.反过来,
int* array = (int*) malloc(sizeof(int)*n);
Run Code Online (Sandbox Code Playgroud)
会创建相同数量的内存,但在堆上.在这种情况下,该内存中的内容与范围无关,只有内存的引用受范围的限制.这里是按值传递和按引用传递的地方.正如您可能知道的那样,传递值意味着当某个东西传递给函数或从函数返回时,传递的"东西"是评估变量的结果.换一种说法,
int n = 4;
printf("%d", n);
Run Code Online (Sandbox Code Playgroud)
将打印数字4,因为构造n评估为4(对不起,如果这是基本的,我只想覆盖所有基础).这4与你的程序的内存空间完全没有关系或关系,它只是一个文字,所以一旦你离开了4具有上下文的范围,你就会失去它.通过参考传递怎么样?通过引用传递在函数的上下文中没有区别; 您只需评估传递的构造.唯一的区别是在评估传递的"事物"之后,您将评估结果用作内存地址.我曾经有一个特别愤世嫉俗的CS导师,他喜欢说没有通过引用传递这样的东西,只是一种传递聪明价值的方法.真的,他是对的.所以现在我们考虑功能方面的范围.假装你可以有一个数组返回类型:
int[] foo(args){
result[n];
// Some code
return result;
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是结果计算到数组的第0个元素的地址.但是当您尝试从此函数外部(通过返回值)访问此内存时,您遇到了问题,因为您正在尝试访问不在您正在使用的作用域内的内存(函数调用的堆栈).因此,我们解决这个问题的方法是使用标准的"传递参考"jiggery-pokery:
int* foo(args){
int* result = (int*) malloc(sizeof(int)*n));
// Some code
return result;
}
Run Code Online (Sandbox Code Playgroud)
我们仍然得到一个指向数组第0个元素的内存地址,但现在我们可以访问该内存了.
我的观点是什么?在Java中,通常断言"一切都是通过价值传递".这是真的.上面同样的愤世嫉俗的教师也对Java和OOP有这样的说法:一切都只是一个指针.他也是对的.虽然Java中的所有内容实际上都是按值传递的,但几乎所有这些值实际上都是内存地址.所以在Java中,该语言确实允许您返回数组或字符串,但它通过将其转换为带有指针的版本来实现.它还为您管理您的记忆.而自动内存管理虽然有用但效率不高.
这将我们带到了C++.C++被发明的全部原因是因为Bjarne Stroustrup在他的博士工作期间一直在试验Simula(基本上是原始的OOPL),并且认为它在概念上很棒,但是他注意到它的表现非常糟糕.所以他开始研究C with Classes,它被重命名为C++.在这样做的过程中,他的目标是制作一种编程语言,该语言采用了Simula的一些最佳功能,但仍然保持强大和快速.由于其已经具有传奇色彩的表现,他选择扩展C,并且一个权衡是他选择不像其他OOPL那样大规模地实现自动内存管理或垃圾收集.从其中一个模板类返回一个数组是有效的,因为你正在使用一个类.但是如果你想返回一个C数组,你必须以C方式进行.换句话说,C++确实支持以与Java相同的方式返回数组; 它只是没有为你做所有的工作.因为一个丹麦人认为它太慢了.
Cas*_*Cow 31
C++确实支持它 - 好吧:
vector< string> func()
{
vector<string> res;
res.push_back( "hello" );
res.push_back( "world" );
return res;
}
Run Code Online (Sandbox Code Playgroud)
甚至C类支持它:
struct somearray
{
struct somestruct d[50];
};
struct somearray func()
{
struct somearray res;
for( int i = 0; i < 50; ++i )
{
res.d[i] = whatever;
}
// fill them all in
return res;
}
Run Code Online (Sandbox Code Playgroud)
A std::string是一个类但是当你说一个字符串时,你可能意味着一个文字.您可以安全地从函数返回文字,但实际上您可以静态创建任何数组并从函数返回它.如果它是一个const(只读)数组,这就是字符串文字的情况,这将是线程安全的.
您返回的数组会降级为指针,因此您无法仅从返回时计算出其大小.
如果可能的话,返回一个数组,首先必须是固定长度,因为编译器需要创建调用堆栈,然后出现数组不是l值的问题,因此在调用函数中接收它必须使用带有初始化的新变量,这是不切实际的.由于同样的原因,返回一个也可能是不切实际的,尽管它们可能对返回值使用了特殊的符号.
请记住,在C的早期,所有变量都必须在函数的顶部声明,并且您不能在第一次使用时声明.因此,当时这是不可行的.
他们给出了将数组放入结构的解决方法,这就是它现在必须保留在C++中的原因,因为它使用相同的调用约定.
注意:在Java等语言中,数组是一个类.你创建一个新的.你可以重新分配它们(它们是l值).
Dav*_*eas 26
C中的数组(以及C++中的向后兼容性)具有与其他类型不同的特殊语义.特别是,对于其余类型,C只具有按值传递的语义,在数组的情况下,传值语法的效果以奇怪的方式模拟传递引用:
在函数签名中,类型为T的N个元素的类型数组的参数将转换为指向T的指针.在函数调用中,将数组作为参数传递给函数会将数组衰减为指向第一个元素的指针,并将该指针复制到函数中.
由于对阵列的这种特殊处理 - 它们不能通过值传递 - 它们也不能通过值返回.在C中你可以返回一个指针,在C++中你也可以返回一个引用,但是数组本身不能在栈中分配.
如果你想到它,这与你在问题中使用的语言没有什么不同,因为数组是动态分配的,你只返回一个指针/引用.
另一方面,C++语言为该特定问题提供了不同的解决方案,例如std::vector在当前标准中使用(内容是动态分配的)或std::array在即将推出的标准中(内容可以在堆栈中分配,但可能会有更高的成本) ,因为在编译器无法省略副本的情况下,必须复制每个元素.实际上,您可以使用与现有标准相同类型的方法,使用现成的库boost::array.
"你不能从函数返回数组,因为该数组将在函数内声明,然后它的位置就是堆栈帧.但是,当函数退出时,堆栈帧被擦除.函数必须从堆栈帧复制返回值以返回位置,这对阵列来说是不可能的."
从这里的讨论:
http://forum.codecall.net/cc/32457-function-return-array-c.html
其他人说在C++中,一个使用vector <>而不是从C继承的数组.
那么为什么C++不允许返回C数组呢?因为C没有.
为什么C没有?因为C是从B演化而来的,这是一种无类型的语言,其中返回数组根本没有意义.当向B添加类型时,使得返回数组成为可能是有意义的但是为了使某些B成语保持有效并且使程序从B到C的转换变得容易而没有这样做.从那时起,可能性使C数组更可用,因为它总是被拒绝(甚至更多,甚至没有考虑),因为它会破坏太多的现有代码.
| 归档时间: |
|
| 查看次数: |
22847 次 |
| 最近记录: |