string** flowFile() {
string line;
string word[8];
int i=0;
static string flow[23][2];
ifstream myfile ("test.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
strSplit(line,word);
flow[i][0]=word[1];
flow[i++][1]=word[2];
}
myfile.close();
}
else cout << "Unable to open file";
return flow;
}
int main()
{
string **fl=flowFile();
}
我收到此错误:
error: cannot convert ‘std::string (*)[2] {aka std::basic_string<char> (*)[2]}’
to ‘std::string** {aka std::basic_string<char>**}’
in return
我的代码出了什么问题?
答案 0 :(得分:3)
string flow[23][2]
和string **
是两种不同的不兼容类型。一个人无法隐式转换为另一个。就这样。解决方案是通过使后面的string [23][2]
返回引用和接受引用来使它们兼容,但这仍然是一个糟糕的解决方案,因为您仍在使用原始数组。
一个好的解决方案是使用std::vector
和std::string
。也许,您还需要std::pair
或std::array
。
以下是一种可能的解决方案:
#include <vector>
#include <array>
#include <string>
//C++11 style typedef
using flow_data_t = std::vector<std::array<std::string,2>>;
//reimplementation of your function
flow_data_t flowFile()
{
std::string line;
std::string word[8];
int i=0;
flow_data_t flow;
std::ifstream myfile ("test.txt");
if ( !myfile )
cout << "Unable to open file";
while ( std::getline (myfile,line) )
{
strSplit(line,word);
flow.push_back({word[0], word[1]});
}
return flow;
}
int main()
{
flow_data_t data=flowFile();
for(auto const & row : data)
for(auto const & col : row)
//work!
}
希望有所帮助。
答案 1 :(得分:1)
std::vector
。您应该使用这些,而不是使用[]
声明的低级内置数组。string [23]
有时可与string*
互换,但string[23][2]
永远不能与string**
互换。这是你不应该使用内置数组的一个原因。答案 2 :(得分:1)
即使您可以返回指针并让数组衰减为指针,也无法从函数返回数组:Array Decay
然而,由于数组的memory layout与&#34; 2D指针数组&#34;不同,因此2D数组既不会衰减到T*
也不会T**
。 (它实际上更像是扁平的),并且你不能从函数返回数组。但是在C ++中,您可以返回数组引用Full Code:
//This does not work
//typedef string * string2d[2];
//typedef string *(&string2d)[2];
typedef string (&string2d)[23][2];
string2d flowFile() {
static string flow[23][2];
return flow;
}
数组引用甚至可以保留每行和每列有多大的信息,并且不会发生数组衰减。
当然,更有建议的&#34; C ++方式&#34;要做到这一点,请使用std::vector
(一如既往)。
答案 3 :(得分:1)
返回指向静态变量的指针没有错。只是必须正确声明返回类型。如果您尝试重现声明的含义以及编译器相应尝试执行的操作,那么这是有意义的。考虑声明static string flow[23][2];
。它声明了23行字符串,每行包含2个元素。如果您将其视为一维数组,它会有所帮助。事实上,数组元素是数组,但现在不是那么重要(但我们会回到它)。从这个角度来看,数组只有23个元素,每个元素的大小为2个字符串。与所有数组一样,元素(这里:2个字符串的arrys)只是在内存中排列。
与任何数组一样,flow
在大多数情况下都会衰减为指向其第一个元素的指针。增加指针将指向下一个元素,即第二行。在数值上,编译器必须将2 * sizeof(字符串)添加到流的地址,以便计算流的下一个元素的地址,这将是流[1]。 (它直接来自流[0]。这里没有魔法。)
现在,如果你声明string **flowpp
,则flowpp已经是一个指针,不需要衰减。如果我们认为它指向数组中的第一个元素,那么这些元素会有什么类型?果然:简单的指针。增加flowpp会让它指向下一个元素。我的指针大4字节,因此在数字上将 4 添加到flowpp就足以访问flowpp的下一个元素。与需要添加到流程中的内容相比(记住,2 * sizeof(字符串)),这完全不同。 编译器根据指针指向的内容计算元素的偏移量!在两种情况下,这是非常不同的。
那么可以你的函数返回什么?当你返回时,流量会衰减到什么程度?它衰减到指向其第一个元素的指针。元素是两个字符串的数组。它必须是string xxx[2]
,xxx是指针:因此string (*p)[2]
。如果指针实际上是由函数返回的,那么我们有一个函数调用而不是普通的p,所以它是(*f())[2]
。
这是一个完整的例子:
#include<iostream>
using namespace std;
const int numFlowElems = 3, numArrElems = 2;
/** @return a pointer to the first element of a static array
of string[numArrElems]s.
*/
string (*flowFile())[numArrElems]
{ // init so that we see something below.
static string flow[numFlowElems][numArrElems]
= {{"1","2"},
{"3","4"},
{"5","6"}
};
// your function code ...
return flow;
}
int main()
{
// array decays to ptr, like usual. Ptr elems are string[numArrElems].
// ptrToArr is a pointer to arrays of two strings.
string (*ptrToArr)[numArrElems] = flowFile();
for( int flowInd= 0; flowInd<numFlowElems; ++flowInd )
{
for(int strInd = 0; strInd<numArrElems; ++strInd)
{
cout << ptrToArr[flowInd][strInd] << ' ';
}
cout << endl;
}
return 0;
}
你如何解析string (*flowFile())[numArrElems]
?我需要两次尝试才能使声明正确,如果这是任何安慰。关键是在C和C ++中(不在C#中,请注意!)声明具有表达式的形状。
你可以从内到外:flowFile()是一个函数。结果被取消引用,因为函数调用的优先级高于星号:* flowFile()是解除引用的结果。显然,结果是一个大小为numArrElems的数组,其元素是字符串。
你可以在外面执行:(*flowFile())[numArrElems]
的结果被声明为字符串。 (*flowFile())
是一个包含numArrElems元素的字符串数组。显然必须取消引用flowFile()
才能获得该数组,以便flowfile是一个返回指向numArrElems字符串数组的指针的函数。这是真的!它返回flow的第一个元素,它正是一个字符串数组。
载体载体可能确实更容易;如果你想保留语义,你应该传递引用,正如其他人提到的:毕竟,原始程序中的所有函数都将在同一个静态数组上运行。如果按值传递向量,则不再是这种情况。但那时,这实际上可能是有益的。