因此,我使用一些XML文件,并且想要创建一个函数来读取XML文件并返回一个包含参数及其值之类的数组。到目前为止,我已经能够读取正确的值。当我使一个const char * read()函数并包含底部的代码并返回const char *时,就会发生我的问题。它必须是const char *,因为解析XML文件的返回值是const char *。我如何做一个函数,该函数返回可以在其他函数中读取的数组?
我尝试使用阅读的示例中的指针,但是它给了我:cannot convert 'const char*[3][2] to int* in assignement.
如何在不出现类型错误的情况下正确使用这些指针指向数组?
#include <QCoreApplication>
#include <iostream>
#include <stdio.h>
#include <tinyxml.h>
#include <sstream>
using namespace std;
int main (void)
{
const char* ptr;
ptr = read();
cout<<ptr[0][0]<<endl;
return 1;
}
const char* read()
{
//READING XML FILE
const char* pFilename = "Profile.xml";
TiXmlDocument doc (pFilename);
if(!doc.LoadFile()) return 1;
const char *xmlread [3][2] = {0};
TiXmlElement *pRoot, *pParm;
int i = 0;
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i][0] = pParm->Attribute("name");
xmlread[i][1] = pParm->Attribute("value");
pParm = pParm->NextSiblingElement("Parameter");
cout<<xmlread[i][0]<<endl;
cout<<xmlread[i][1]<<endl;
i++;
}
}
return xmlread;
}
答案 0 :(得分:3)
您正在用C ++而不是C编写程序,因此您实际上根本不应该使用原始指针!仅仅因为XML库返回的值为const char*
并不意味着您必须这样做。尤其是由于您试图返回XML文档所拥有的指针,而该XML文档在函数退出时会被破坏,从而使存储在数组中的所有指针均无效。
如果您绝对需要使用原始指针返回字符串数组(在C ++中则不会!),它看起来会像这样:
#include <QCoreApplication>
#include <iostream>
#include <tinyxml.h>
#include <stdio.h>
using namespace std;
char* myStrDup(const char *s)
{
//return strdup(s);
int len = strlen(s);
char *ptr = new char[len+1];
memcpy(ptr, s, len);
ptr[len] = '\0';
return ptr;
}
char*** read(int *count)
{
*count = 0;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (!doc.LoadFile())
return NULL;
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
++(*count);
pParm = pParm->NextSiblingElement("Parameter");
}
}
char ***xmlread;
int i = 0;
try
{
xmlread = new char**[*count];
try
{
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i] = new char*[2];
try
{
xmlread[i][0] = NULL;
xmlread[i][1] = NULL;
try
{
xmlread[i][0] = myStrDup(pParm->Attribute("name"));
xmlread[i][1] = myStrDup(pParm->Attribute("value"));
}
catch (...)
{
delete[] xmlread[i][0];
delete[] xmlread[i][1];
throw;
}
}
catch (...)
{
delete[] xmlread[i];
throw;
}
++i;
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
catch (...)
{
for (int j = 0; j < i; ++j)
{
delete[] xmlread[j][0];
delete[] xmlread[j][1];
delete[] xmlread[j];
}
delete[] xmlread;
throw;
}
}
catch (...)
{
return NULL;
}
return xmlread;
}
int main()
{
int count;
char*** ptr = read(&count);
if (ptr)
{
for(int i = 0; i < count; ++)
{
cout << ptr[i][0] << endl;
cout << ptr[i][1] << endl;
}
for(int i = 0; i < count; ++)
{
delete[] ptr[i][0];
delete[] ptr[i][1];
delete[] ptr[i];
}
delete[] ptr;
}
return 0;
}
不是很好,不是吗?您可以通过返回一个数组,使它稍微好一点,该数组的元素是用于容纳字符串指针的结构类型:
#include <QCoreApplication>
#include <iostream>
#include <tinyxml.h>
#include <stdio.h>
using namespace std;
struct NameValue
{
char *name;
char *value;
NameValue() : name(NULL), value(NULL) {}
~NameValue() { delete[] name; delete[] value; }
};
char* myStrDup(const char *s)
{
//return strdup(s);
int len = strlen(s);
char *ptr = new char[len+1];
memcpy(ptr, s, len);
ptr[len] = '\0';
return ptr;
}
NameValue* read(int *count)
{
*count = 0;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (!doc.LoadFile())
return NULL;
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
++(*count);
pParm = pParm->NextSiblingElement("Parameter");
}
}
NameValue *xmlread;
int i = 0;
try
{
xmlread = new NameValue[*count];
try
{
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i].name = myStrDup(pParm->Attribute("name"));
xmlread[i].value = myStrDup(pParm->Attribute("value"));
++i;
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
catch (...)
{
delete[] xmlread;
throw;
}
}
catch (...)
{
return NULL;
}
return xmlread;
}
int main()
{
int count;
NameValue* ptr = read(&count);
if (ptr)
{
for (int i = 0; i < count; ++i)
{
cout << ptr[i].name << endl;
cout << ptr[i].value << endl;
}
delete[] ptr;
}
return 0;
}
但是,在C ++中,最好的选择是让您的函数返回std::vector
,而结构类型将为字符串保留std::string
个成员。让C ++标准库为您处理所有内存管理:
#include <QCoreApplication>
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <tinyxml.h>
using namespace std;
struct NameValue
{
string name;
string value;
};
vector<NameValue> read()
{
vector<NameValue> xmlread;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (doc.LoadFile())
{
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
NameValue elem;
elem.name = pParm->Attribute("name");
elem.value = pParm->Attribute("value");
xmlread.push_back(elem);
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
return xmlread;
}
int main()
{
try
{
vector<NameValue> elems = read();
for (vector<NameValue>::size_type i = 0; i < elems.size(); ++i)
{
cout << elems[i].name << endl;
cout << elems[i].value << endl;
}
/* or:
for (vector<NameValue>::iterator iter = elems.begin(); iter != elems.end(); ++iter)
{
cout << iter->name << endl;
cout << iter->value << endl;
}
*/
/* or:
for (auto &elem : elems)
{
cout << elem.name << endl;
cout << elem.value << endl;
}
*/
}
catch (const exception &e)
{
cerr << e.what() << endl;
}
return 0;
}
答案 1 :(得分:1)
const char* ptr; ... cout<<ptr[0][0]<<endl;
这可能行不通。如果ptr
是指向一个字符数组(n个数组)的指针,则ptr[0]
是一个字符对象(特别是指向的字符数组的第一个字符)。由于没有用于参数[0]
和char
的下标运算符,因此在该字符上进一步应用int
格式不正确。
TiXmlDocument doc (pFilename); ... xmlread[i][0] = pParm->Attribute("name"); ... return xmlread;
您已将doc
声明为自动变量。自动变量在声明它们的作用域结尾处自动自动销毁。 Attribute
成员函数返回指向文档拥有的内存的指针。 TiXmlDocument
的析构函数将销毁所拥有的内存,并且在函数返回后,数组xmlread
中的指针将悬空。悬空指针指向的内存访问行为是不确定的。
xmlread
数组本身也是一个自动变量,并且在read
的末尾也被销毁。无法从函数中返回数组,而返回指向数组的指针只会导致指针悬空。
最后,当您尝试返回指向char的指针数组时,返回类型为“ char的指针”的问题。那简直是畸形的。
您可以从诸如std::vector
之类的函数返回容器。您可以使用包含std::string
实例的类将2d数组的“行”结构化为可读形式。雷米在另一个答案中向您展示了如何在实践中做到这一点。
有没有一种方法可以正确使用指针,而不必更改数组和添加结构类型?
好吧,如果您可以更改数组的保留位置,那么对代码的最小修复是将数组放入main
,并将对它的引用传递到read
,这样{ {1}}可以填充它。您还必须对read
做同样的事情。