更新:C++ 指针片段

Posted

技术标签:

【中文标题】更新:C++ 指针片段【英文标题】:UPDATE: C++ Pointer Snippet 【发布时间】:2009-02-15 02:58:05 【问题描述】:

再次问候,再次感谢为第一个问题提供答案的所有人。以下代码已更新为包含每个分配的两个函数。

要查看原始问题,请点击here。

非常确信这满足了任务的要求,但我再次非常感谢任何帮助。我是否适当地修改了删除语句?再次感谢。

#include<iostream>
#include<string>

int** createArray(int, int);
void deleteArray(int*[], int);

using namespace std;

int main()

    int nRows;
    int nColumns;

    cout<<"Number of rows: ";
    cin>>nRows;

    cout<<"Number of columns: ";
    cin>>nColumns;

    int** ppInt = createArray(nRows, nColumns);

    deleteArray(ppInt, nRows);


int** createArray(int nRows, int nColumns)

    int** ppInt = new int*[nRows];

    for (int nCount = 0; nCount < nRows; nCount++)
    
        ppInt[nCount] = new int[nColumns];
    

    return ppInt;


void deleteArray(int** nPointer, int nRows)

    for (int nCount = 0; nCount < nRows; nCount++)
    
        delete[] nPointer[nCount];
    

    delete[] nPointer;

附:这是作业文档本身,以防万一:

(1) 设计并实现一个为二维整数数组分配内存的函数:该函数应该接受两个整数作为参数,一个为行数,一个为列数。您需要在此函数中使用“new”运算符。请记住,我们需要首先创建一个指针数组。然后,对于该数组中的每个指针,我们需要创建一个整数数组。这个函数应该返回一个指向二维整数数组的指针。

(2) 设计并实现一个函数来为这个二维数组释放内存:该函数应该有两个参数(一个指向二维整数数组的指针,另一个是数字数组中的行数)。在函数中,您应该使用“delete”运算符为这个二维数组取消分配内存。您应该首先删除每一行(整数数组),然后删除指针数组。

【问题讨论】:

【参考方案1】:

代码看起来不错。

但是,对于我们人类来说,您可能想要解决一些问题:

    您的函数签名(声明)缺少参数名称。更适合:

    int** createArray(int rows, int columns); void deleteArray(int** array, int rows);

    您的函数名称对于它们真正创建/删除的内容没有太多描述性。例如,create2DArray 将是一个更明智的选择。

    变量的n 前缀伤害了我的眼睛。 numRowsrowCount 更具可读性。 同样,ppInt 也很疯狂。尝试array(也适用于nPointer,以保持一致性)。 (很遗憾,你不能写2dArray。) 使用i 作为循环计数器比nCount 或类似的更常见(尤其是对于数组索引)。我建议你改用它。

一些超越和超越的东西,供您个人练习:

    创建一个将rowscols 作为其构造函数参数的类。确保自动释放数组。 使用std::vector 并为您的类创建一个resize 成员函数。 请注意,这与最初的问题有所不同,后者要求指点。 创建一个copy 函数和一个clone 函数以将数据复制到另一个二维数组(可能具有不同的大小!)或克隆一个现有数组。

【讨论】:

“创建一个复制函数 [...] 将数据复制到另一个二维数组”复制构造函数有什么问题? 从未提及 :) 我认为您的意思是 2 个函数然后没有之前提出的类 :) 非常感谢您的意见。这段代码并不是真正要实现的……作业的目的是展示对内存管理的理解。我的教授要求变量名前加一个字母来表示数据类型;他还需要描述性的变量名 'i' 在我看来是一个描述性的变量名。 'nCount' 让我想到'计数',这没有意义。至少将其设为“nCounter”或“nIndex”。 @strager:如果教授想要一个伪匈牙利符号,他可能会得到它 - 但我同意 i 比 nCount 更容易阅读。【参考方案2】:

没关系。

问题在于您没有考虑代码中的异常安全性。

int** ppInt = new int*[nRows];   // ALLOC 1

for (int nCount = 0; nCount < nRows; nCount++)

        ppInt[nCount] = new int[nColumns]; // ALLOC 2

说 ALLOC 1 没问题。 但是,如果 ALLOC 2 中的任何一个失败,那么您就会遇到异常和严重的内存泄漏。

例如。 你在第四次调用 ALLOC 2 时失败了。然后你从 ALLOC 1 和前三个调用 ALLOC 2 泄漏内存。现在在你的情况下,代码是如此微不足道,它可能无关紧要。但这是您在编写 C++ 代码时应始终牢记的事情。

如果抛出异常,这里会发生什么,哪些资源会被泄露,哪些资源不会被正确清理。

我认为您应该考虑将二维数组包装在一个类中,这样即使存在异常,您也可以保证正确分配和取消分配内存。

【讨论】:

感谢您的洞察力。不幸的是,异常处理和调试是我的教授都没有花太多时间讨论的主题。绝对是我需要花时间研究的两个领域。 不错的收获,@Martin York。 (双关语无意。)但是,操作系统会捕获异常,这将终止进程并释放其内存(在这种情况下)。此外,NULL 上的 delete[](以防异常被禁用)被忽略,因此 deleteArray 没有问题需要担心。 @strager:这对于这个简单的例子来说很好。但在任何实际代码中,这通常不是一个选项。在简单的示例中学习如何正确执行此操作将为您在现实生活中节省更多时间。【参考方案3】:

在我看来是合理的。

不过,我不确定是否要提交一个全新的问题。作为对原版的修正,它可能会更好。

【讨论】:

感谢您的意见。如果第二个问题不恰当,我深表歉意;我没有看到修改原始问题的选项。下次我会记住这一点。再次感谢你。保重。 我想我应该刚刚编辑了原始帖子。再次道歉,非常感谢您查看代码。【参考方案4】:

对于“deleteArray”,你的原型和定义并不完全相同:

void deleteArray(int*[], int);
void deleteArray(int** nPointer, int nRows)

它们确实具有相同的含义,但为了清楚起见,我认为最好让它们完全相同(使用 `int**' 来强调您正在传递指针的事实)以保持一致性。

另外,在原型中包含参数名称。

【讨论】:

啊,谢谢你指出这一点……我完全错过了。然而,这个错误教会了我一些东西。我不知道这两种形式在语法上是相同的。再次感谢!

以上是关于更新:C++ 指针片段的主要内容,如果未能解决你的问题,请参考以下文章

在tablayout片段之间进行通信[重复]

片段中的空指针异常

访问片段的子视图时出现空指针异常

空指针异常 - 片段活动

片段 getArguments() 空指针异常

从活动调用片段方法时出现空指针异常