nev*_*ind 6 c memory malloc memory-management segmentation-fault
我在@GWW的帮助下想到了这段代码,但现在我不能free了char**。
这是我的代码(它只是读取输入文件并在屏幕上打印名称):
/* deallocate2D
corresponding function to dynamically deallocate 2-dimensional array using
* malloc.
* accepts a char** as the "array" to be allocated, and the number of rows.
* as with all dynamic memory allocation, failure to free malloc'ed memory
* will result in memory leaks
*/
void deallocate2D(char** array, int nrows) {
/* deallocate each row */
int i;
for (i = 0; i < nrows; i++) {
free(array[i]);
}
/* deallocate array of pointers */
free(array);
}
int readInputFile(FILE *fp, char **file_images) {
num_lines = 0;
int s = 10;
char line[MAX_LENGTH];
char **final_filenames;
while (fgets(line, sizeof line, fp) != NULL) /* read a line */ {
if (line[0] != '\n') {
if (num_lines >= s) {
s += 100;
if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
}
}
if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL) {
printf("Error allocating space for 2d array: %s\n", strerror(errno));
return -1;
}
strncpy(file_images[num_lines], line, MAX_LENGTH);
if (file_images[num_lines] == NULL) {
printf("Strncpy failed: %s\n", strerror(errno));
return -1;
}
printf("name of file %d is: %s \n", num_lines, file_images[num_lines]);
num_lines++;
}
}
printf("Num_lines: %d\n",num_lines);
//realloc to number of lines in the file, to avoid wasting memory
if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
} else {
file_images = final_filenames;
deallocate2D(final_filenames, num_lines);
}
return 0;
//don't forget to free lines 2d array! (here or at the end of the code)
}
int main(int argc, char *argv[]) {
//pixel* image;
char **images_filenames;
//check parameters
if (argc < 4) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm charWidth charHeight \"\n");
return -1;
}
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) {
printf("Error allocating initial space for 2d array: %s\n", strerror(errno));
return -1;
}
if (readInputFile(fpin, images_filenames) == -1) {
printf("Error reading image filenames from input\n");
return -1;
}
fclose(fpin);
printf("###########\n");
deallocate2D(images_filenames, num_lines);
printf("Done!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所以,我不明白为什么我free final_filenames和images_filenames。
这段代码给我的错误是:
*** glibc detected *** ./main: double free or corruption (!prev): 0x0986d228 ***
Run Code Online (Sandbox Code Playgroud)
如何正确无误地free排列我的阵列?
Jon*_*ler 11
问题是您正在释放可能已经释放的指针,并且您不知道正在使用多少空间,没有指向最近分配的空间的指针(通常),因此您无法释放准确地记忆。在中main(),您具有:
char **images_filenames;
[...]
if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) {
[...]
if (readInputFile(fpin, images_filenames) == -1) {
[...]
deallocate2D(images_filenames, num_lines);
Run Code Online (Sandbox Code Playgroud)
您分配10个字符指针,然后将该数组传递给readInputFile()函数。在该函数内部,有代码重新分配该数组,但是您没有为主程序提供一种了解新地址是什么的方法。这样做的方法是通过将指针传递到要修改的内容,或者让函数返回修改后的值(或者您采取诸如使用全局变量而不是参数的肮脏做法,但您不应该这样做)。
因此,您需要:
if (readInputFile(fpin, &images_filenames) == -1) {
Run Code Online (Sandbox Code Playgroud)
在readInputFile()函数中,您需要进行很多更改-处理三指针参数的较大更改,然后是各种编码问题:
int readInputFile(FILE *fp, char ***ppp_files)
{
num_lines = 0;
int s = 10;
char line[MAX_LENGTH];
char **file_images = *ppp_files;
char **final_filenames;
Run Code Online (Sandbox Code Playgroud)
更新: 我没有注意到这只是初始化num_lines,没有声明它。因此,num_lines必须是某种全局变量...下面的一些注释需要进行调整以允许这种情况。
到目前为止,这种变化(几乎)是微不足道的。我们得到一个指向'char **'的指针,因此是三指针参数。为了简化以下代码,请在旧名称(file_images)下创建参数的本地副本,并使用参数所指向的值对其进行初始化。随后的代码可以继续使用file_images;只需确保在返回之前更新参数即可。
除...
您假设's = 10',但是实际上,您应该让main函数告诉您有多少行可用。它确实分配了10行,但是如果没有仔细检查的话,情况尚不清楚。您应该让main()程序说出预分配了多少行-该函数的额外参数。您还面临一个问题,main()程序无法告知deallocate2D()函数数组中有多少行,因为它不知道。目前尚不清楚您的代码如何编译。您在num_lines这里有一个局部变量,但是有一个对变量的引用,在该变量num_lines中main()没有声明。局部变量将屏蔽所有全局变量。
while (fgets(line, sizeof line, fp) != NULL) {
if (line[0] != '\n') {
if (num_lines >= s) {
s += 100;
Run Code Online (Sandbox Code Playgroud)
添加大量行是一个好主意;它“摊销”了重新分配的成本。
if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL)
Run Code Online (Sandbox Code Playgroud)
但是,您使用的技术存在一些特定的问题。纯代码样式:当一行包含if带有嵌入式分配的,并且行变得太长时,请在条件之前将分配拆分:
file_images = (char**) realloc(file_images, s * sizeof (char*));
if (file_images == NULL)
Run Code Online (Sandbox Code Playgroud)
现在只剩下一个细微的错误。如果realloc()失败怎么办...
没错,您已经泄漏了内存,因为in中的file_images值为null,因此无法释放它以前指向的内容。 永远不要写:
x = realloc(x, size);
Run Code Online (Sandbox Code Playgroud)
故障时会泄漏内存!因此,您需要:
char **new_space = realloc(file_images, s * sizeof (char*));
if (new_space == NULL)
{
printf("Error reallocating space for 2d array: %s\n",
strerror(errno));
*ppp_files = file_images;
return -1;
}
}
Run Code Online (Sandbox Code Playgroud)
通常,错误消息应打印在stderr; 上。我还没有解决。
请注意,我小心地将的最后一个(非null)值复制回file_images了主程序中的变量。也可以对大小进行相同的操作(另一个接口更改),或者使用一种结构封装数组-大小和指向其基址的指针,可能是合适的。
if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL)
{
printf("Error allocating space for 2d array: %s\n", strerror(errno));
return -1;
}
Run Code Online (Sandbox Code Playgroud)
需要设置此错误返回*ppp_files = file_images;。
strncpy(file_images[num_lines], line, MAX_LENGTH);
if (file_images[num_lines] == NULL) {
printf("Strncpy failed: %s\n", strerror(errno));
return -1;
}
Run Code Online (Sandbox Code Playgroud)
这个测试很奇怪。您知道那file_images[num_lines]不是null,strncpy()也不会改变它。您不需要测试和错误处理。
printf("name of file %d is: %s \n", num_lines, file_images[num_lines]);
num_lines++;
}
}
printf("Num_lines: %d\n",num_lines);
Run Code Online (Sandbox Code Playgroud)
好...
//realloc to number of lines in the file, to avoid wasting memory
Run Code Online (Sandbox Code Playgroud)
很好 这几乎不值得;即使在64位计算机上,您最多也浪费不到1 KiB。但是,保持整洁无害-好。
if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) {
printf("Error reallocating space for 2d array: %s\n", strerror(errno));
return -1;
Run Code Online (Sandbox Code Playgroud)
同样,您需要*ppp_files = file_images;在返回之前进行设置。
} else {
file_images = final_filenames;
Run Code Online (Sandbox Code Playgroud)
这不会影响main()程序中的值。它需要 *ppp_files = file_images;再次出现。
deallocate2D(final_filenames, num_lines);
Run Code Online (Sandbox Code Playgroud)
等等-您要释放所有精心分配的空间吗?因此,您毕竟不会使用它吗?上面的分配只是在附近复制了一个指针值;它没有复制内存...
}
return 0;
//don't forget to free lines 2d array! (here or at the end of the code)
}
Run Code Online (Sandbox Code Playgroud)
此注释是错误的-成功返回后,内存已被释放。
随机猜测-您无需使用“ vim”或其他“ vi”派生词进行编辑。在第1列中确实有其功能的大括号的人,因为这样您就可以使用' ]]'或' [[' 在文件中向前或向后跳转到下一个或上一个功能的开头。在不起作用的地方使用代码非常麻烦。
好吧,这是一个开始的诊断……这是使用结构来中继文件名数组的工作代码。我readInputFile()使用复制自结构之外的局部变量离开了函数的主体,并确保始终正确更新结构。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
enum { MAX_LENGTH = 512 };
typedef struct FileNameArray
{
size_t nfiles; /* Number of file names allocated and in use */
size_t maxfiles; /* Number of entries allocated in array */
char **files; /* Array of file names */
} FileNameArray;
static void deallocate2D(FileNameArray *names)
{
for (size_t i = 0; i < names->nfiles; i++)
free(names->files[i]);
free(names->files);
names->nfiles = 0;
names->files = 0;
names->maxfiles = 0;
}
static int readInputFile(FILE *fp, FileNameArray *names)
{
int num_lines = names->nfiles;
int max_lines = names->maxfiles;
char **file_names = names->files;
char line[MAX_LENGTH];
char **final_filenames;
while (fgets(line, sizeof line, fp) != NULL)
{
if (line[0] != '\n')
{
/* Remove newline from end of file name */
char *nl = strchr(line, '\n');
if (nl != 0)
*nl = '\0';
if (num_lines >= max_lines)
{
max_lines += 100;
char **space = realloc(file_names, max_lines * sizeof (char*));
if (space == NULL)
{
fprintf(stderr, "Error reallocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->maxfiles = max_lines;
names->files = space;
file_names = space;
}
if ((file_names[num_lines] = malloc(strlen(line) + 1)) == NULL)
{
fprintf(stderr, "Error allocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->nfiles++;
strcpy(file_names[num_lines], line);
printf("name of file %d is: %s \n", num_lines, file_names[num_lines]);
num_lines++;
}
}
printf("Num_lines: %d\n", num_lines);
//realloc to number of lines in the file, to avoid wasting memory
if ((final_filenames = realloc(file_names, num_lines * sizeof (char*))) == NULL)
{
fprintf(stderr, "Error reallocating space for 2d array: %s\n",
strerror(errno));
return -1;
}
names->maxfiles = num_lines;
names->files = final_filenames;
return 0;
}
int main(int argc, char *argv[])
{
FileNameArray names = { 0, 0, 0 };
//check parameters
if (argc < 4)
{
fprintf(stderr, "Usage: %s input_filename.ppm charWidth charHeight\n",
argv[0]);
return -1;
}
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
fprintf(stderr, "Could not open input file %s (%s)\n",
argv[1], strerror(errno));
return -1;
}
if ((names.files = malloc(10 * sizeof (char*))) == NULL)
{
fprintf(stderr, "Error allocating initial space for 2d array: %s\n",
strerror(errno));
return -1;
}
names.maxfiles = 10;
if (readInputFile(fpin, &names) == -1)
{
fprintf(stderr, "Error reading image filenames from input\n");
return -1;
}
fclose(fpin);
printf("###########\n");
deallocate2D(&names);
printf("Done!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)