C 无法重新定位双指针动态内存

C 无法重新定位双指针动态内存,c,memory,malloc,realloc,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) *

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

#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;
}
#包括
#包括
无效更改缓冲区大小(字符**缓冲区)
{
*buffer=realloc(*buffer,sizeof(char)*2);
}
int main()
{
char**buffer=malloc(sizeof(char)*1);
*缓冲区[0]=“H”;
更改缓冲区大小(缓冲区);
*缓冲区[1]=“i”;
printf(“%s\n”,*缓冲区);
返回0;
}
我得到
分段错误(堆芯转储)
错误

char **buffer = malloc(sizeof(char) * 1); 
这是错误的。您现在有了一个
char**
,因此它指向的是一个
char*
,但是里面只有足够的空间容纳
char
。您还只分配了一层双指针

*buffer[0] = 'H';
由于上述问题,该线路导致SEG故障。它试图在未定义的位置写入内存

解决这一问题的最佳方法是正常分配第一层,必要时使用
&
,第二层仅使用
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;
}
#包括
#包括
无效更改缓冲区大小(字符**缓冲区)
{
*buffer=realloc(*buffer,sizeof(char)*3);
}
int main()
{
char*buffer=malloc(sizeof(char)*1);
缓冲区[0]=“H”;
更改缓冲区大小(&buffer);
缓冲区[1]=“i”;
缓冲区[2]='\0';
printf(“%s\n”,缓冲区);
返回0;
}

您已经有了一个很好的答案,但是关于
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终止字符结尾。您不能简单地分配
缓冲区[0]='H'
并将
缓冲区
视为字符串。nul termianting字符(
'\0'
,或简称
0
)必须跟在后面,因此需要
缓冲区[1]=0printf(“%s\n”,*buffer)之前的code>

避免在代码中使用幻数。您的
change\u buffer\u 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 */
}
内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(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)
始终确认已释放所有已分配的内存,并且没有内存错误


仔细检查一下,如果有问题请告诉我。

非常感谢您提供的解决方案。您能告诉我如何在
更改缓冲区大小
功能中修改缓冲区吗?例如,
buffer[1]=“i”在realloc之后。我再次遇到分段错误。@请注意,
buffer
change\u buffer\u size
main
中是不同的类型。您在
main
中编写的内容是正确的,但在
change\u buffer\u size
中,您需要执行
(*buffer)[1]='i'改为。再次感谢。你能详细解释一下我为什么要使用这种语法吗?@vortex因为
缓冲区
是一个
字符**
,所以你需要先做
(*buffer)
来得到
字符*
,然后再做
[1]
获取一个
字符
,您最终可以将其写入
'i'
中。您仍然调用未定义的行为—在
printf中将
缓冲区
视为字符串(“s\n”,buffer)时缺少nul终止字符
buffer
短了一个。始终使用临时指针
realloc
。当
realloc
失败时,它返回
NULL
,这将覆盖原始指针,导致内存泄漏。例如,
void*tmp=realloc(*buffer*2*sizeof**buffer);如果(!tmp){perror(“realloc tmp”);return;}*缓冲区=tmp;}我刚刚意识到:y
$ 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)