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



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

#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("%sn", *buffer);
return 0;
}

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

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] = '';
printf("%sn", buffer);
return 0;
}

你已经有一个很好的答案@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结尾字符结尾。不能简单地分配buffer[0] = 'H';buffer视为字符串。nul-termianting字符('',或简称0(必须跟随,所以在调用printf("%sn", *buffer);之前需要buffer[1] = 0;

避免在代码中使用魔术数字。您的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)

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

仔细看看,如果你有问题,请告诉我。

最新更新