如何解决分配和释放动态内存
我编写了一个短程序,它从存储卡中读取 JPEG 并将 JPEG 作为单独的文件作为输出写入。该程序按我的预期工作,但我知道我的代码编写得很差,因为没有从堆中释放动态内存。
我曾尝试在我的代码中使用 fclose()
和 free()
,但在我这样做时出现以下错误:
free(): double free detected in tcache 2
Aborted
我已经注释掉了这些函数,并且我的代码按预期工作。 我想知道为什么当我尝试使用这两个函数时它不起作用。我做错了什么?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// define/declare variables
typedef uint8_t BYTE;
FILE *outptr;
int main(int argc,char *argv[])
{
// declare variables
int counter = 0;
// ensure correct command-line useage
if (argc != 2)
{
printf("Useage: ./recover memorycard\n");
return 1;
}
// open memory card to read
FILE *inptr = fopen(argv[1],"r");
if (inptr == NULL) // ensure enough memory
{
fprintf(stderr,"Could not open file");
return 2;
}
// read into infile,512 bytes at a time until end of file
BYTE buffer[512];
while (fread(buffer,sizeof(BYTE),512,inptr) == 512)
{
// if JPEG headerfile is found
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if (counter > 0) // if not first JPEG
{
// close prevIoUs file
// fclose(outptr); // here is the issue
// free(outptr); // and here
}
// allocate memory for new file
char *outfile = malloc(sizeof(BYTE) * 512);
if (outfile == NULL)
{
printf("Not enough memory for output file\n");
fclose(inptr);
return 3;
}
// write new file name
sprintf(outfile,"%03i.jpg",counter);
// open new file
outptr = fopen(outfile,"w");
if (outptr == NULL)
{
fprintf(stderr,"Could not open file.\n");
fclose(inptr);
return 4;
}
// write 512 bytes from infile into new file
fwrite (buffer,outptr);
counter++;
}
// if not start of new JPEG
else if (buffer[0] != 0xff || buffer[1] != 0xd8 || buffer[2] != 0xff || (buffer[3] & 0xf0) != 0xe0)
{
// if already found JPEG
if (counter > 0)
{
// keep writing into JPEG
fwrite (buffer,outptr);
}
continue;
}
}
// Close remaining files once gone through memory card
// fclose(inptr); // here
// free(inptr); // and here
}
解决方法
在循环的第一次迭代中,outptr
变量未初始化,因此对其执行的任何操作都会带来未定义的行为。
具体来说,您没有为它分配任何从 fopen()
获得的值,因此您不应该 fclose()
它。
此外,您还没有为它分配从 malloc()
或 calloc()
获得的任何值,因此您不应free()
它。
当您需要写入文件时,您需要 fopen()
一个文件,只要需要(您写入它)就保留一个指向它的指针,并在完成后 fclose()
。文件处理不需要 malloc()
和 free()
。
以下是稍微简化的代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// define/declare variables
typedef uint8_t BYTE;
FILE *outptr = NULL;
int main(int argc,char *argv[])
{
// declare variables
int counter = 0;
// ensure correct command-line useage
if (argc != 2)
{
printf("Useage: ./recover memorycard\n");
return 1;
}
// open memory card to read
FILE *inptr = fopen(argv[1],"r");
if (inptr == NULL) // ensure enough memory
{
fprintf(stderr,"Could not open file");
return 2;
}
// read into infile,512 bytes at a time until end of file
BYTE buffer[512];
while (fread(buffer,sizeof(BYTE),512,inptr) == 512)
{
// if JPEG headerfile is found
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if (outptr != NULL) // previous file is opened
{
fclose(outptr); // close it
}
char outfilename[ 512]; // output file name
sprintf(outfilename,"%03i.jpg",counter ++);
// open new file
outptr = fopen(outfilename,"w");
if (outptr == NULL)
{
fprintf(stderr,"Could not open file.\n");
fclose(inptr);
return 4;
}
}
// whether it's a new or still the same file...
if(outptr != NULL)
{
// keep writing into JPEG
fwrite (buffer,outptr);
}
}
fclose(outptr); // close the last file created
fclose(inptr); // as well as the input
}
我删除了对文件名的 malloc
调用 - 它足够短,可以在堆栈上自动分配,并且您不需要在使用后free
(您忘记这样做了),顺便说一句,因此造成内存泄漏...)
我注意到您在 write
和 if
分支中执行完全相同的 else
,因此我将其移到了条件之外。
我还删除了 continue;
指令,因为一旦控制到达右大括号,循环就会继续。
最重要的是:我添加了初始化 FILE* outptr = NULL;
以便它可以检查文件指针变量是否已成功打开文件,而不是检查明显未连接的 {{1} } 变量。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// define byte
typedef uint8_t BYTE;
int main(int argc,char *argv[])
{
// ensure correct command-line useage
if (argc != 2)
{
printf("Useage: ./recover memorycard\n");
return 1;
}
// open memory card
FILE *inptr = fopen(argv[1],"r");
if (inptr == NULL)
{
fprintf(stderr,"Could not open file");
return 2;
}
// buffer for file names
char output[8];
// keep track of file number for file names
int counter = 0;
// pointer to write JPEGs to
FILE *outptr = NULL;
// read into infile,inptr) == 512)
{
// New JPEG signatiture found
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// if not first JPEG,close previous output file
if (outptr != NULL)
fclose(outptr);
// write new file name
sprintf(output,counter);
// open new file
outptr = fopen(output,"Could not open file.\n");
fclose(inptr);
return 4;
}
// increment file counter
counter++;
}
// if output file is already open
if (outptr != NULL)
{
// keep writing into JPEG
fwrite (buffer,outptr);
}
}
// close final file if still open
if (outptr != NULL)
fclose(inptr);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。