简体   繁体   English

从函数返回const char *数组

[英]Returning const char* array from function

So I am with some XML files and I want to make a function that reads an XML file and returns an array that includes things like parameters and their values. 因此,我使用一些XML文件,并且想要创建一个函数来读取XML文件并返回一个包含参数及其值之类的数组。 So far, I am able to read the correct values. 到目前为止,我已经能够读取正确的值。 My problem occurs when I make a const char* read() function and include the code that is in the bottom, and return const char*. 当我使一个const char * read()函数并包含底部的代码并返回const char *时,就会发生我的问题。 It has to be const char* because the return value from parsing the XML file is a const char*. 它必须是const char *,因为解析XML文件的返回值是const char *。 How do I make a fuction that returns an array that I am able to read in a different function? 我如何做一个函数,该函数返回可以在其他函数中读取的数组? I tried using pointers from an example I read, but it gives me: cannot convert 'const char*[3][2] to int* in assignement. 我尝试从阅读的示例中使用指针,但是它给了我: cannot convert 'const char*[3][2] to int* in assignement.

How do I use these pointers to arrays properly without gtting a type error? 如何正确使用这些指向数组的指针而不会出现类型错误?

#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; 
}

You are writing a program in C++, not C, so you really should not be using raw pointers at all! 您正在用C ++而不是C编写程序,因此您实际上根本不应该使用原始指针! Just because the XML library returns values as const char* does not mean you have to do the same. 仅仅因为XML库将值返回为const char*并不意味着您必须做同样的事情。 Especially since you are trying to return pointers owned by an XML document that is destroyed when your function exits, thus invalidating any pointers you store in the array. 特别是由于您试图返回XML文档所拥有的指针,而该XML文档在函数退出时会被破坏,从而使存储在数组中的所有指针均无效。

If you absolutely need to return an array of strings using raw pointers (which you don't in C++!), it would look something more like this instead: 如果您绝对需要使用原始指针返回一个字符串数组(您在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;
}       

Not so nice, is it? 不太好,是吗? You could make it slightly nicer by returning an array whose elements are a struct type to hold the string pointers: 您可以通过返回一个数组,使它稍微好一些,该数组的元素是一种结构类型,用于保存字符串指针:

#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;
}

However, in C++, the best option is to have your function return a std::vector instead, where the struct type holds std::string members for the strings. 但是,在C ++中,最好的选择是让函数返回一个std::vector ,其中struct类型保存std::string成员。 Let the C++ standard library handle all of the memory management for you: 让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;
}
 const char* ptr; ... cout<<ptr[0][0]<<endl; 

This cannot possibly work. 这可能行不通。 If ptr is pointer to a(n array of) character, then ptr[0] is a character object (specifically, the first character of the pointed array of characters). 如果ptr是指向一个字符的(n个数组)的指针,则ptr[0]是一个字符对象(特别是指向的字符数组的第一个字符)。 Further applying [0] on that character is ill-formed since there is no subscript operator for arguments char and int . 由于对该参数charint没有下标运算符,因此对该字符进一步应用[0]格式不正确。

 TiXmlDocument doc (pFilename); ... xmlread[i][0] = pParm->Attribute("name"); ... return xmlread; 

You've declared doc as an automatic variable. 您已将doc声明为自动变量。 Automatic variables are destroyed automatically at the end of the scope where they are declared. 自动变量在声明它们的作用域末尾自动销毁。 Attribute member function returns pointers to memory owned by the document. Attribute成员函数返回指向文档拥有的内存的指针。 The destructor of TiXmlDocument will destroy the owned memory, and the pointers in the array xmlread will be dangling after the function has returned. TiXmlDocument的析构TiXmlDocument将销毁所拥有的内存,并且在函数返回后,数组xmlread的指针将悬空。 The behaviour of accessing memory pointed by a dangling pointer is undefined. 悬空指针指向的内存访问行为是不确定的。

The xmlread array itself is also an automatic variable, and is destroyed at the end of read as well. xmlread数组本身也是一个自动变量,在read结束时也会被销毁。 It is not possible to return an array out of a function, and returning a pointer to an array would simply result in a dangling pointer. 从函数中返回数组是不可能的,而返回指向数组的指针只会导致指针悬空。

Finally there is the problem that the return type is "pointer to char", while you're attempting to return an array of arrays of pointers to char. 最后,当您尝试返回指向char的指针数组时,返回的类型是“ char的指针”的问题。 That is simply ill-formed. 那简直是畸形的。


You can return containers from a function such as std::vector . 可以从诸如std::vector类的函数返回容器。 You can structure the "rows" of your 2d array into a readable form using a class that contains instances of std::string . 您可以使用包含std::string实例的类将2d数组的“行”结构化为可读形式。 Remy has shown you how to do this in practice in another answer. 雷米在另一个答案中向您展示了如何在实践中做到这一点。

Is there a way to use pointers correctly instead of having to change my array and add struct types? 有没有一种方法可以正确使用指针,而不必更改我的数组和添加结构类型?

Well, if you can change where you keep the array, then a minimal fix to your code is to put the array into main , and pass a reference to it into read , so that read can fill it. 好吧,如果你能改变你保持数组,然后最小修复你的代码是把数组转换成main ,并通过对它的引用到read ,使read能填补它。 You must also do the same for TiXmlDocument . 您还必须对TiXmlDocument做同样的TiXmlDocument

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM