从函数返回const char *数组

时间:2018-10-31 21:34:53

标签: c++ arrays

因此,我使用一些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; 
}

2 个答案:

答案 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做同样的事情。