无法重新分配双指针动态内存

时间:2020-01-04 02:35:31

标签: c memory malloc realloc

我试图在另一个方法/函数中增加双指针缓冲区。但是,分配的缓冲区的大小不会更改。这是我尝试的代码。

#include <stdio.h>
#include <stdlib.h>

void change_buffer_size(char ** buffer)
{
     *buffer = realloc(*buffer, sizeof(char) * 2);
}

int main()
{
    char **buffer = malloc(sizeof(char) * 1); 
    *buffer[0] = 'H';
    change_buffer_size(buffer);
    *buffer[1] = 'i';
    printf("%s\n", *buffer);
    return 0;
}

我收到Segmentation fault (core dumped)错误。

2 个答案:

答案 0 :(得分:1)

char **buffer = malloc(sizeof(char) * 1); 

这是错误的。现在您有了一个char**,因此它指向的内容是一个char*,但是其中只有一个足够的空间容纳char。您还只分配了双指针的一层。

*buffer[0] = 'H';

由于上述问题,此行导致段错误。它试图在未定义的位置写入内存。

解决此问题的最佳方法是正常分配第一层,必要时使用&,第二层仅使用malloc

此外,%s直到看到空字节都不会停止写入,因此您需要分配并写入其中一个。解决方法如下:

#include <stdio.h>
#include <stdlib.h>

void change_buffer_size(char ** buffer)
{
     *buffer = realloc(*buffer, sizeof(char) * 3);
}

int main()
{
    char *buffer = malloc(sizeof(char) * 1); 
    buffer[0] = 'H';
    change_buffer_size(&buffer);
    buffer[1] = 'i';
    buffer[2] = '\0';
    printf("%s\n", buffer);
    return 0;
}

答案 1 :(得分:1)

@JosephSible已经给您一个很好的答案,但是还有一点需要考虑使用realloc。我在原始问题下的评论中提到了这一点。使用realloc时,必须始终使用临时指针realloc来捕获realloc的返回值。

为什么?当(不是)realloc失败时,它将返回NULL。如果将返回值直接分配给您要为其重新分配的指针,则将指针覆盖到现有内存块,而NULL会丢失对原始块的引用,从而导致内存泄漏。例如,您不想:

    *buffer = realloc (*buffer, 2);       /* sizeof(char) is always 1 */

相反,在将重新分配的块分配给原始指针之前,请使用临时指针并验证重新分配是否成功,例如

    void * tmp = realloc (*buffer, 2);
    if (!tmp) {     /* validate EVERY allocation & reallocation */
        perror ("realloc-*buffer");
        exit (EXIT_FAILURE);        /* or handle as desired, e.g return NULL, etc.. */
    }
    *buffer = tmp;  /* now assign the reallocated block to your pointer */

对您的原始帖子有几条评论。用C调用的字符串必须以 nul-termination 字符结尾。您不能简单地分配buffer[0] = 'H';并将buffer视为字符串。必须遵循 nul-termianting 字符('\0'或简称0),因此在调用buffer[1] = 0;

之前,您需要printf("%s\n", *buffer);

避免在代码中使用魔术数字。您的change_buffer_size()函数使用幻数2对重新分配的大小进行硬编码。 (不是很有用)。而是至少传递所需的大小作为参数,以便您的函数可重复使用,例如

char *change_buffer_size (char **buffer, size_t nchar)
{
    void *tmp = realloc (*buffer, nchar * sizeof **buffer);
    if (!tmp) { /* validate EVERY allocation/reallocation */
        perror ("change_buffer_size()-realloc");
        return NULL;
    }

    return *buffer = tmp;   /* assign new block to *buffer, return */
}

注意:将返回类型更改为char*允许您通过返回指示函数的成功/失败,并在成功时直接访问重新分配的内存块)

现在,您想将缓冲区重新分配给2个字符,只需将2传递为nchar,依此类推。再加上一个简短的示例,该示例重新分配了一个字符并将其添加到缓冲区中时间(同时确保始终为 nul终止)可能如下所示:

#include <stdio.h>
#include <stdlib.h>

char *change_buffer_size (char **buffer, size_t nchar)
{
    void *tmp = realloc (*buffer, nchar * sizeof **buffer);
    if (!tmp) { /* validate EVERY allocation/reallocation */
        perror ("change_buffer_size()-realloc");
        return NULL;
    }

    return *buffer = tmp;   /* assign new block to *buffer, return */
}

int main (void) {

    size_t nchar = 1;   /* character counter */
    char *str = "hello world!", *buffer = NULL;

    for (int i = 0; str[i]; i++) {
        if (!change_buffer_size(&buffer, nchar + 1))    /* alloc nchar + 1 */
            return 1;
        buffer[nchar-1] = str[i];           /* copy char from str to buffer */
        buffer[nchar++] = 0;                /* nul-terminate buffer */
        printf ("buffer: '%s'\n", buffer);  /* print current buffer contents */
    }

    free (buffer);      /* don't forget to free what you allocate */
}

注意:,请不要忘记free()分配的内存。是的,这里将在程序退出时释放它,但会提早养成良好的习惯-您将不会总是如此在main()中工作)

使用/输出示例

$ ./bin/realloccharbuf
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)不再需要它时可以释放

当务之急是使用一个内存错误检查程序来确保您不尝试访问内存或不在分配的块的边界之外/之外写,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于Linux,valgrind是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

$ valgrind ./bin/realloccharbuf
==19740== Memcheck, a memory error detector
==19740== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19740== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==19740== Command: ./bin/realloccharbuf
==19740==
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'
==19740==
==19740== HEAP SUMMARY:
==19740==     in use at exit: 0 bytes in 0 blocks
==19740==   total heap usage: 13 allocs, 13 frees, 1,114 bytes allocated
==19740==
==19740== All heap blocks were freed -- no leaks are possible
==19740==
==19740== For counts of detected and suppressed errors, rerun with: -v
==19740== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认已释放已分配的所有内存,并且没有内存错误。

仔细研究一下,如果您有任何疑问,请告诉我。

相关问题