C ++中奇怪的内存管理问题(至少从初学者开始)

时间:2011-01-20 18:06:11

标签: c++ arrays memory-management cstring

我是C ++的新手,我有很多Objective-C经验。

我正在尝试将一个c字符串数组(即char **)作为我的类中的实例变量,它在我的构造函数中被分配和填充,然后在另一个我想要的成员函数中打印出整个“网格”。

分配工作,我用字符串填充我的数组(现在只是“aaaaaaa”等等)。检查我的构造函数的结尾,我看到每一行都已成功创建并按预期填充。

然而,我然后调用我的printGrid()函数,然后事情变得奇怪。如果我要打印25行,比如说,前12个左右会打印出垃圾,剩下的13个按预期打印出来。所以我似乎在某处践踏记忆,我不确定在哪里。

我的代码可能看起来有点乱,因为我一直在尝试不同的东西,所以我会尽量让它看起来尽可能具有凝聚力。

main.cpp:我在哪里调用函数

#include <iostream>
#include "Bitmap.h"

using namespace std;
int main (int argc, char * const argv[]) {

    Bitmap bitmap(15, 25);
    bitmap.printBitmap();

    return 0;
}

Bitmap.h:我班级的标题

class Bitmap {
private:
    char **_bitmap;
        void printLine(char const*lineString);
    int _width;
    int _height;
public:
    Bitmap();
        Bitmap(int width, int height);
    void printBitmap();
};

Bitmap.cpp:行动发生的地方

#include <iostream>
#include "Bitmap.h"

using namespace std;
Bitmap::Bitmap() {
    // allocate space for the bitmap
    int numRows = 20;
    int numColumns = 30;

    Bitmap(numRows, numColumns); // Can I even safely do this? I'm not using the default constructor in my main() but I'm still curious.
}

Bitmap::Bitmap(int width, int height) {
    _width = width;
    _height = height;

    _bitmap = (char **)malloc(sizeof(char*) * height); // FIXED this line (used to be char, now it's char *).
    for (int currentRow = 0; currentRow < height; currentRow++) {
        _bitmap[currentRow] = (char *)malloc((sizeof(char) * width));
        snprintf(_bitmap[currentRow], width, "%s", "1");

        for (int currentColumn = 0; currentColumn < width; currentColumn++) {
            _bitmap[currentRow] = strcat(_bitmap[currentRow], "a");
        }
        printf("currentRow %0d: %s\n",currentRow, _bitmap[currentRow]); // Each row prints out FINE here, as expected
    }
}

void Bitmap::printBitmap() {
    int numColumns =_width;
    int numRows = _height;

    if (NULL == _bitmap)
        return;

    // iterate over the bitmap, line by line and print it out
    for (int currentRow = 0; currentRow < numRows; currentRow++) {

        // If there are, say, 25 lines, the first 12 or so will be garbage, then the remaining will print as expected
        printLine((char const *)_bitmap[currentRow]);
    }
}

void Bitmap::printLine(char const*lineString) {
    printf(":%s\n", lineString);    
}

这是针对学校的,教授不允许使用C ++向量或字符串。否则,是的我知道我应该使用那些。感谢您的所有建议。

8 个答案:

答案 0 :(得分:6)

红旗:

_bitmap = (char **)malloc(sizeof(char) * height);

应该是

_bitmap = (char **)malloc(sizeof(char*) * height);

您需要指向char*的指针,而不是指向char的指针。

答案 1 :(得分:5)

_bitmap = (char **)malloc(sizeof(char) * height);

应该是

_bitmap = (char **)malloc(sizeof(char*) * height);

并且只有在您编码C时才会这样做。

如果您绝对需要位图是连续的,那么最好使用new / delete,

Vector< Vector < char > > 

如果你不这样做。

另外,strcat似乎是一个奇怪的选择,因为你还没有初始化内存。即不一定是0,所以字符串没有结束。这可能会导致你的记忆踩踏。尝试使用strcpy(如果你想要安全,请使用strncpy)。

答案 2 :(得分:4)

与默认构造函数中的此注释相关:

Bitmap(numRows, numColumns); // Can I even safely do this? I'm not using
                             // the default constructor in my main() but
                             // I'm still curious.

这不符合你的想法。这是调用其他构造函数进行额外的初始化。相反,这会使用BitmapnumRows创建另一个临时未命名的numColumns对象,然后立即调用其析构函数。此语句的作用类似于没有名称的局部变量。

在您的情况下,您可以通过给出一个构造函数默认参数来提供默认构造函数:

public:
    Bitmap(int width = 20, int height = 30);

答案 3 :(得分:4)

这个malloc没有为字符串末尾的0字节留出空间:

    _bitmap[currentRow] = (char *)malloc((sizeof(char) * width));

由于“sizeof(char)”的定义是1,你可以这样做:

    _bitmap[currentRow] = (char *)malloc(width+1);

在这个结构中:

    for (int currentColumn = 0; currentColumn < width; currentColumn++) {
        _bitmap[currentRow] = strcat(_bitmap[currentRow], "a");
    }

你真的不想使用strcat,只需直接分配字符:

    for (int currentColumn = 0; currentColumn < width; currentColumn++) {
        _bitmap[currentRow][currentColumn] = 'a';
    }
    _bitmap[currentRow][width] = 0; // and don't forget to terminate the string

答案 4 :(得分:1)

除了所有其他答案:

Bitmap::Bitmap() {
    // allocate space for the bitmap
    int numRows = 20;
    int numColumns = 30;

    Bitmap(numRows, numColumns); // Can I even safely do this? I'm not using the default constructor in my main() but I'm still curious.
}

不,你不能这样做。每个构造函数都是独立的,它们不能相互委派。

对于内存管理,请使用专用资源管理类,它们将自动为您控制内存。该标准提供了一系列优秀的课程,std::vector<std::string>将在这种情况下很好地服务于此目的。

答案 5 :(得分:0)

以下 应正确分配(尚未测试)。

_bitmap = new char*[height];
for (int currentRow = 0; currentRow < height; currentRow++) 
{         
    _bitmap[currentRow] = new char[width];         
    snprintf(_bitmap[currentRow], width, "%s", "1");          
    for (int currentColumn = 0; currentColumn < width; currentColumn++) 
    {             
        _bitmap[currentRow] = strcat(_bitmap[currentRow], "a");         
    }                 // Each row prints out FINE here, as expected     

    printf("currentRow %0d: %s\n",currentRow, _bitmap[currentRow]); 
} 

还要确保定义复制构造函数,析构函数和赋值运算符,以确保内存不会泄漏并删除数组。

答案 6 :(得分:0)

这里我认为你想要malloc

中的sizeof(char *)
_bitmap = (char **)malloc(sizeof(char) * height);

另外,当你用“a”填充字符串时,你必须确保你没有覆盖任何内存:你分配了宽度字符,你打印“1”,然后连接“a”宽度时间,将超过分配的内存1(更不用说没有留下任何空间终止

答案 7 :(得分:0)

你的malloc()电话对我来说不合适,但也许我错过了一些东西。

我应该看到的是malloc()对数组存储的调用。如果你想要10个C字符串,那就是malloc(10 * sizeof (char *))。然后我应该看到更多的malloc()调用实际分配10个字符串本身使用的内存。

但我只看到一个malloc()调用,似乎认为它是分配字符串数组内存,而不是字符串指针数组内存。