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]=0调用printf(“%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)