【问题标题】:Problems with dynamic memory allocation for structs in CC中结构的动态内存分配问题
【发布时间】:2018-12-12 10:37:30
【问题描述】:

我收到了未知数量的“宽符号”。文本被格式化为句子,我必须将其添加到结构“文本”中。

这些是我的结构:

struct Sentence {
    wchar_t *sentence;
    int amount_of_symbols;
};

struct Text {
    struct Sentence *sentences;
    int amount_of_sentences;
}; 

我为“句子”结构的数组动态分配内存并添加它们。 这是我的输入代码:

int amount_of_sentences = 0;
struct Sentence *sentences = (struct Sentence *) malloc(amount_of_sentences * sizeof(struct Sentence));

struct Text text = {sentences, amount_of_sentences};

wchar_t symbol;
int buffer_size = 0;
wchar_t *buffer = (wchar_t *) malloc(buffer_size * sizeof(wchar_t));

bool sentence_begun = true;

while (true) {
    symbol = getwchar();

    if (symbol == '\n')
        break;

    if (sentence_begun && symbol == ' ') {
        sentence_begun = false;
        continue;
    }

    buffer = (wchar_t *) realloc(buffer, (++buffer_size) * sizeof(wchar_t));
    buffer[buffer_size - 1] = symbol;

    if (symbol == '.') {
        buffer[buffer_size] = '\0';

        text.amount_of_sentences++;
        text.sentences = (struct Sentence *) realloc(text.sentences, text.amount_of_sentences * sizeof(struct Sentence));
        text.sentences[text.amount_of_sentences - 1].amount_of_symbols = buffer_size;
        text.sentences[text.amount_of_sentences - 1].sentence = (wchar_t *) malloc(buffer_size * sizeof(wchar_t));
        text.sentences[text.amount_of_sentences - 1].sentence = buffer;

        buffer_size = 0;
        buffer = (wchar_t *) realloc(buffer, buffer_size * sizeof(wchar_t));
        sentence_begun = true;
    }
}

一切似乎都很好,但是当我尝试输出我的所有句子时,并不是所有的句子都显示出来,并且有些重复。

这是我的输出代码:

for (int i = 0; i < text.amount_of_sentences; i++) {
    wprintf(L"%ls\n", text.sentences[i].sentence);
}

输入输出示例:

adjsand. asdad.a.a. aaaa. adsa.


a.

adsa.
adsa.

这段代码有什么问题,我应该改变什么?

【问题讨论】:

  • 您能否说明textsentence_begun 是如何声明和初始化的?
  • @Schwern, int amount_of_sentences = 0; struct Sentence *sentences = (struct Sentence *) malloc(amount_of_sentences * sizeof(struct Sentence)); struct Text text = {sentences, amount_of_sentences}; bool sentence_begun = true;
  • Please edit your question 这样代码示例就更完整了。
  • @Schwern,修改完毕

标签: c struct malloc realloc wchar-t


【解决方案1】:

问题就在这里。

    text.sentences[text.amount_of_sentences - 1].sentence = (wchar_t *) malloc(buffer_size * sizeof(wchar_t));
    text.sentences[text.amount_of_sentences - 1].sentence = buffer;

    buffer_size = 0;
    buffer = (wchar_t *) realloc(buffer, buffer_size * sizeof(wchar_t));

您用malloc 分配一个新句子,然后用buffer 覆盖它。这会泄漏内存。

然后将buffer 分配给text.sentences[text.amount_of_sentences - 1].sentence,然后通过重新分配buffer 来释放该内存。

来自 C 标准...

realloc 函数释放 ptr 指向的旧对象,并返回一个指向具有 size 指定大小的新对象的指针。

text.sentences[text.amount_of_sentences - 1].sentence 最终指向已释放的内存。这将导致未定义的行为。

改为指向buffer 并分配一个新的buffer

    text.sentences[text.amount_of_sentences - 1].sentence = buffer;

    buffer_size = 0;
    buffer = malloc(buffer_size * sizeof(wchar_t));

其他一些注意事项...

As Paul noted,你需要为空字节分配一个额外的字节。

There's no need to cast the result of malloc or realloc.

在堆栈上分配一个大缓冲区来读取输入(如果需要,增加它)更简单、更快、更不容易出错。然后将内容复制到适当大小的内存中。

I went ahead and coded up an improved version 来说明。如果这是家庭作业,请不要交。

【讨论】:

  • 它有帮助。谢谢 Schwern 和 Paul Ogilvie!
  • @НикитаБабенко 不客气。我继续编写了一个带有我正在谈论的改进的版本。 gist.github.com/schwern/75f4bf42baf36042a5416cf782438438 用作说明,但如果这是作业请不要作为自己的作业上交。
【解决方案2】:

首先,您的缓冲区 1 太小,不考虑终止 '\0'。在程序的顶部,执行:

int buffer_size = 1;
wchar_t *buffer = (wchar_t *) malloc(buffer_size * sizeof(wchar_t));
*buffer= '\0';

但真正的问题在于:

    text.sentences[text.amount_of_sentences - 1].sentence =
                (wchar_t *) malloc(buffer_size * sizeof(wchar_t));
    text.sentences[text.amount_of_sentences - 1].sentence = buffer;

    buffer_size = 0;
    buffer = (wchar_t *) realloc(buffer, buffer_size * sizeof(wchar_t));

您为句子分配内存,然后用buffer 指针覆盖该指针。接下来重置缓冲区大小并重新分配缓冲区。

分配确实复制缓冲区数据。为此,请执行以下操作:

    strcpy(text.sentences[text.amount_of_sentences - 1].sentence, buffer);

这里也是这样:

buffer_size = 1;
buffer = (wchar_t *) realloc(buffer, buffer_size * sizeof(wchar_t));
*buffer= '\0';

【讨论】:

  • 它没有帮助。输出与第一个类似。
  • 我忘记了... buffer[buffer_size] = '\0'; 应该是 buffer[buffer_size-1] = '\0'; 如果这不能解决问题(而且我找不到任何代码错误),您必须将程序放在调试器并单步执行,检查每一步是否仍然正常。
  • 另外:amount_of_symbols = buffer_size -1; 因为最后一个字符是'\0'
  • 和:buffer[buffer_size - 2] = symbol; 出于同样的原因。
  • @PaulOgilvie strcpywchar_t * 是否安全?