将char [] []分配给char **

时间:2016-02-19 20:15:06

标签: c++ arrays

我正在进行一项任务,我们需要给出一个二维数组,我们需要进行一些计算。

我想将计算的逻辑封装到它自己的类中,所以在我的计算类中我有成员char **,我试图用给定的char arr [5] [5]初始化。我首先尝试做一个c风格的演员,让它编译,但如果我试图尊重我的成员变量会导致段错误。

简而言之,为什么这不起作用

 class MyClass{
      Myclass(char arr[5][5]){
        m_PmyArr = arr; //doesn't work
     }
     char** m_PmyArr;
 };

为什么这会编译,但会在取消引用后导致段错误

class MyClass{
     Myclass(char arr[5][5]){
        m_PmyArr = (char**)arr; //will compile, but will segfault
     }
     char** m_PmyArr;
 };

我希望这不会被解释为"我的工作对我而言,我真的一直试图更好地掌握指针的细微差别,这与我之前理解的关系是相反的。数组和指针

8 个答案:

答案 0 :(得分:5)

int[5][5]int**不同。虽然数组在传递给函数时可以衰减为指针,但这并不会发生在多个数组级别。所以两者无法转换。

即使你使指针兼容,你也需要考虑指针的来源。如果它来自局部变量,并且该对象比它创建的函数更长,则指针将变为无效。

您应该动态分配内存:

 class MyClass{
      Myclass(int rows, int cols){
        int i;
        this->rows = rows;
        this->cols = cols;
        m_PmyArr = new int*[rows];
        for (i=0; i<rows; i++) {
            m_PmyArr[i] = new int[cols];
        }
     }
     ~Myclass() {
        int i;
        for (i=0; i<rows; i++) {
            delete[] m_PmyArr[i];
        }
        delete[] m_PmyArr;
     }
     char** m_PmyArr;
     int rows, cols;
 };

答案 1 :(得分:4)

一旦你通过单个间接指针,我发现从概念上开始思考这些结构意味着什么是有帮助的。这是一张图片,说明char**之间的差异,它指向char* ...和char[5][5]的外观。

enter image description here

这两者不可互换。使用char[5][5]时,您无法指向指向char的指针...因为每个“元素”不是char*,而是char[5]。 ..你需要一个指向的指针

答案 2 :(得分:3)

m_PmyArr的类型为char**,而在m_PmyArr = arr语句中,arr(在衰变后)的类型为char (*)[5]m_PmyArrarr都是不兼容的类型 将arr强制转换为char**只会关闭编译器警告,忽略程序的任何错误行为。

答案 3 :(得分:2)

数组和指针很难处理,这就是你通常只使用std::vectorstd::string等的原因。

让我们来看看你的构造函数:

Myclass(char arr[5][5])

这并不意味着您的意思。数组不能通过值传递;据说数组“衰减”到指向其第一个元素的指针。这正是这里发生的事情。

你的构造函数等同于以下语法怪物:

Myclass(char(*arr)[5])

(您可以通过将其添加到您的班级来轻松验证这一点。您的编译器应该抱怨重新定义。)

怎么来的?考虑一下:二维数组实际上是一维数组,只是它的元素类型有点特殊。就像数组int arr[5]由5个int元素组成一样,数组char arr[5][5]由5个char[5]元素组成。根据这一观察,我们可以得出结论 char[5]是一种类型

换句话说,构造函数真正接收的是指向数组的第一个元素的指针,其中每个元素都是char[5]

m_PmyArr = arr; //doesn't work

是的,因为m_PmyArr的元素属于char*类型,而不属于char[5]。编译器阻止您分配指向不兼容类型的指针。

  

为什么这会编译,但会在取消引用后导致段错误

     

[...]

    m_PmyArr = (char**)arr; //will compile, but will segfault

因为C样式转换会禁用编译器的错误检查工具。

正式地,在您的真实代码中,您可能会遇到未定义的行为,这可能会导致崩溃,因为char*可能需要的机器内存空间少于({1}} char[5] ,所以你的程序可能有一些内存问题。那里有很多“可能”,但这就是未定义行为的本质。

答案 4 :(得分:1)

@IBAction func sendEmailButtonTapped(sender: AnyObject) {
    let mailComposeViewController = configuredMailComposeViewController()
    if MFMailComposeViewController.canSendMail() {
        self.presentViewController(mailComposeViewController, animated: true, completion: nil)
    } else {
        self.showSendMailErrorAlert()
    }
}

func configuredMailComposeViewController() -> MFMailComposeViewController {

    let query = PFQuery(className: "datos_contacto")
    query.getObjectInBackgroundWithId("G5w8G3kVBG", block: {
        (questionObject: PFObject?, error: NSError?) -> Void in

        let direccion: AnyObject! = questionObject!.objectForKey("dato_contacto")

        self.emailConsulta  = direccion as! String

        print("Email=",self.emailConsulta)


    })

    let mailComposerVC = MFMailComposeViewController()
    mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property


    print (emailConsulta)

    mailComposerVC.setToRecipients([emailConsulta])
    mailComposerVC.setSubject("Enviado desde Pedro Villarejo App Clientes (iOs)...")
    mailComposerVC.setMessageBody("Escriba aqui su texto", isHTML: false)

    return mailComposerVC
}
func showSendMailErrorAlert() {
    let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail.  Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
    sendMailErrorAlert.show()
}

// MARK: MFMailComposeViewControllerDelegate

func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
    controller.dismissViewControllerAnimated(true, completion: nil)

}

不正确,因为class MyClass{ Myclass(char arr[5][5]){ m_PmyArr = arr; //doesn't work } char** m_PmyArr; }; 衰减到arr,而不是char (*)[5]

char**

将编译但稍后会导致问题,具体取决于您如何使用成员变量以及用于构造对象的内容,正如您已经注意到的那样。

您可以使用以下内容:

class MyClass{
     Myclass(char arr[5][5]){
        m_PmyArr = (char**)arr; //will compile, but will segfault
     }
     char** m_PmyArr;
 };

答案 5 :(得分:1)

类型不兼容。二维数组实际上是一维数组的并置,类似于一维数组中单个元素的并置。

您应该考虑使用std::vector。但是,如果您希望 - 或者 - 坚持通过指针模拟二维数组,您可能会尝试使用模板。

class C {
    private:
        size_t rows, cols;
        int **matrix;

    public:
        template <size_t NR, size_t NC> C(const int (&m)[NR][NC]) :
            rows(NR), cols(NC), matrix(new int *[NR])
        {
            for(size_t r=0; r<rows; ++r){
                matrix[r]=new int[cols];
                std::copy(m[r], m[r]+cols, matrix[r]);
            }
        }

        ~C(){
            for(size_t r=0; r<rows; r++)
                delete[] matrix[r];
            delete[] matrix;
        }
};

答案 6 :(得分:0)

char **只是一个指向char的指针。为了使它代表一个二维数组,它必须指向一个指针列表,而这些指针又指向行。其他答案显示了这一点你必须手动执行指针算法。

使用char [5] [5],编译器可以计算出所需的内存和指针算法,以便在给定的索引处取消引用。这就是为什么它是一个不同的类型。 char [] [5]可以用作函数参数类型。它告诉编译器一行中有5个字符,因此它知道一行中另一行结束的内存块的位置。

答案 7 :(得分:0)

如果在编译时已知数组大小,您可以使用模板函数来计算数组维度并处理数组中的数据:

#include <iostream>

template <int w, int h>
void f(int(&a)[w][h])
{
    std::cout << "Width: " << w << " Height: " << h << std::endl;
}

int main()
{
    int a1[2][3];
    int a2[4][5];

    f(a1);
    f(a2);
}

当然,如果你想动态分配内存(例如询问用户的尺寸),这将无效。