C++ 中奇怪的内存管理问题(至少对于初学者来说)

发布于 2024-10-13 05:16:06 字数 2510 浏览 8 评论 0原文

我是 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++ 向量或字符串。否则,是的,我知道我应该使用它们。感谢您的所有建议。

I'm new to C++, I have lots of Objective-C experience.

I'm trying to have an array of c-strings (that is char **) as an instance variable in my class, which gets allocated and filled in my constructor, and then in another member function I want to print out the whole "grid".

The allocation works, I fill up my array with strings (just "aaaaaaa" and so on for now). Checking at the end of my constructor, I see that each line has successfully been created and filled as expected.

However, I then call my printGrid() function, and then things go strange. If I've got 25 lines to print, say, the first 12 or so will print garbage, then the remaining 13 print out as expected. So it seems like I'm trampling over memory somewhere, and I'm not sure where.

My code might look a little messy because I've been trying different things, so I'll try to make it look as cohesive as possible.

main.cpp: Where I'm calling the functions

#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: header for my class

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: Where the action happens

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

This is for school and the prof isn't allowing C++ vectors or strings. Otherwise, yes I know I should be using those. Thanks for all the suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

夏至、离别 2024-10-20 05:16:06

危险信号:

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

应该是

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

您想要一个指向 char* 的指针,而不是指向 char 的指针。

Red flag:

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

should be

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

You want a pointer to a char*, not a pointer to a char.

飞烟轻若梦 2024-10-20 05:16:06
_bitmap = (char **)malloc(sizeof(char) * height);

应该

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

并且仅当您正在编码 C 时。

则更好的是使用 new/delete

Vector< Vector < char > > 

如果您绝对需要位图是连续的,或者如果您不需要,

。另外,考虑到您尚未初始化内存,strcat 似乎是一个奇怪的选择。即不一定有0,所以字符串没有结尾。这可能会导致你的记忆力下降。尝试使用 strcpy (如果你想安全的话,可以使用 strncpy )。

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

should be

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

and only if you're coding C.

Better is to use new/delete if you absolutely need the bitmap to be contiguous, and

Vector< Vector < char > > 

if you don't.

Also, strcat seems an odd choice, given that you haven't initialized the memory yet. I.e. there is not necessarily a 0, so no end to the string. That may cause your memory stomp. Try using strcpy (or strncpy if you want to be safe).

九局 2024-10-20 05:16:06

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

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

这不会执行您认为的操作。这不是调用其他构造函数来进行额外的初始化。相反,这会使用 numRowsnumColumns 创建另一个临时未命名 Bitmap 对象,然后立即调用其析构函数。该语句的作用就像一个没有名称的局部变量。

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

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

Related to this comment inside your default constructor:

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

This does not do what you think it does. This is not a call to the other constructor to do additional initialisation. Instead, this creates another temporary unnamed Bitmap object using numRows and numColumns, and then immediately calls its destructor. This statement acts like a local variable with no name.

In your case you can supply a default constructor by giving your one constructor default arguments:

public:
    Bitmap(int width = 20, int height = 30);
╰ゝ天使的微笑 2024-10-20 05:16:06

这个 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,直接赋值char即可:

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

This malloc isn't leaving room for a 0 byte at the end of the string:

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

Since "sizeof(char)" is 1 by definition, you can just do:

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

And in this construct:

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

you don't really want to use strcat, just assign the char directly:

    for (int currentColumn = 0; currentColumn < width; currentColumn++) {
        _bitmap[currentRow][currentColumn] = 'a';
    }
    _bitmap[currentRow][width] = 0; // and don't forget to terminate the string
妞丶爷亲个 2024-10-20 05:16:06

除了所有其他答案之外:

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 在这种情况下将很好地满足目的。

In addition to all the other answers:

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.
}

No, you can't do this. Each constructor is independent and they cannot delegate to each other.

For memory management, use dedicated resource management classes that will automatically control the memory for you. The Standard provides an excellent series of classes and std::vector<std::string> shall serve the purpose in this case excellently.

慕烟庭风 2024-10-20 05:16:06

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

_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]); 
} 

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

The following should allocate correctly (haven't tested it).

_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]); 
} 

Also be sure to define a copy constructor, destructor, and assignment operator to ensure memory doesn't leak and the array gets deleted.

寄与心 2024-10-20 05:16:06

这里我认为你想要 sizeof (char *) inside malloc

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

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

here I think you want sizeof (char *) inside malloc

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

Also, when you are filling the string with "a", you have to make sure you are not overwriting any memory: you allocated width character, you print "1" to it, then concatenate "a" width times, which would go 1 past the allocated memory (not to mention not leave any room for the nul-termination

梦太阳 2024-10-20 05:16:06

您的 malloc() 调用对我来说看起来不正确,但也许我错过了一些东西。

我应该看到的是对数组存储的一次 malloc() 调用。如果您想要其中包含 10 个 C 字符串,则为 malloc(10 * sizeof (char *))。然后我应该会看到更多 malloc() 调用,这些调用实际上分配了 10 个字符串本身使用的内存。

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

Your malloc() call doesn't look right to me, but perhaps I'm missing something.

What I should be seeing is one malloc() call for the storage for the array. If you want 10 C strings in it, that would be malloc(10 * sizeof (char *)). Then I should see some more malloc() calls that actually allocate the memory the 10 strings themselves use.

But I'm only seeing one malloc() call, that appears to think it is allocating string array memory, not string pointer array memory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文