分配和释放动态内存
Allocating and freeing dynamic memory
我编写了一个小程序,可以从存储卡中读取 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, sizeof(BYTE), 512, 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, sizeof(BYTE), 512, 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, sizeof(BYTE), 512, outptr);
}
}
fclose(outptr); // close the last file created
fclose(inptr); // as well as the input
}
我已经删除了对 malloc
的文件名调用 - 它足够短,可以自动分配到堆栈上,并且您不需要在使用后 free
它(您忘记了顺便说一句,因此会造成内存泄漏...)
我注意到你在 if
和 else
分支中做的 write
完全一样,所以我把它移到了条件之外。
我还删除了 continue;
指令,因为一旦控制到达右大括号,循环就会继续。
最重要的是:我添加了初始化 FILE* outptr = NULL;
,因此它可以检查 文件指针 变量是否文件已成功打开,而不是检查一个明显的未连接 counter
变量。
#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, 512 bytes at a time until end of file
BYTE buffer[512];
while (fread(buffer, sizeof(BYTE), 512, 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, "%03i.jpg", counter);
// open new file
outptr = fopen(output, "w");
if (outptr == NULL)
{
fprintf(stderr, "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, sizeof(BYTE), 512, outptr);
}
}
// close final file if still open
if (outptr != NULL)
fclose(inptr);
}
我编写了一个小程序,可以从存储卡中读取 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, sizeof(BYTE), 512, 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, sizeof(BYTE), 512, 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, sizeof(BYTE), 512, outptr);
}
}
fclose(outptr); // close the last file created
fclose(inptr); // as well as the input
}
我已经删除了对 malloc
的文件名调用 - 它足够短,可以自动分配到堆栈上,并且您不需要在使用后 free
它(您忘记了顺便说一句,因此会造成内存泄漏...)
我注意到你在 if
和 else
分支中做的 write
完全一样,所以我把它移到了条件之外。
我还删除了 continue;
指令,因为一旦控制到达右大括号,循环就会继续。
最重要的是:我添加了初始化 FILE* outptr = NULL;
,因此它可以检查 文件指针 变量是否文件已成功打开,而不是检查一个明显的未连接 counter
变量。
#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, 512 bytes at a time until end of file
BYTE buffer[512];
while (fread(buffer, sizeof(BYTE), 512, 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, "%03i.jpg", counter);
// open new file
outptr = fopen(output, "w");
if (outptr == NULL)
{
fprintf(stderr, "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, sizeof(BYTE), 512, outptr);
}
}
// close final file if still open
if (outptr != NULL)
fclose(inptr);
}