首页 > 解决方案 > 从函数返回 const char* 数组

问题描述

所以我有一些 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; 
}

标签: c++arrays

解决方案


你正在用 C++ 编写程序,而不是 C,所以你真的不应该使用原始指针!仅仅因为 XML 库返回值const char*并不意味着您必须这样做。特别是当您试图返回一个 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++ 中,最好的选择是让您的函数返回 a std::vector,其中 struct 类型保存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;
}

推荐阅读