c语言 - 复制字符串 - 如何处理内存泄漏和错误情况?



我正在尝试实现函数int *cpy_array(int v[], int size),它将数组复制到另一个数组中并将新数组作为指针返回。我还必须注意错误情况并使用动态内存。

好的,我知道当没有足够的可用内存时,malloc 返回 0。我想知道是否还有其他可能的错误,我错过了。然后我必须在成功和错误的情况下实现free()。 我尝试实现类似的东西:

if (!w[i]) { 
for (k = 0; k < i; ++k)
free(w[k]); 
return 0;
}

但这总是有一个错误。

In file included from hot.c:2:
C:/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/i686-w64-mingw32/include/stdlib.h:502:27: note: expected 'void *' but argument is of type 'int'"
void __cdecl free(void *_Memory); 

而且我不确定为什么要释放()新数组还是应该释放旧数组?我试图在我的函数中使用指针释放它,但也没有工作,并且认为它不应该在主要位置?

这是原始代码:

int *cpy_array(int v[], int size);
int main(void)
{
int size; 
size = 4;
int myArray[4] = {1234};
if (*cpy_array(myArray, size) == 0)
{
printf("No memory available.");
}else{
printf("The new Array: %i", *cpy_array(myArray, size)); 
}
return 0;
}
int *cpy_array(int v[], int size)
{
int i;
int *a  = malloc(size * sizeof(int));
if(*a == 0)
return 0;
for (i = 0; i < size; i++)
{ 
a[i] = v[i];
}
return a;
}

在第一个代码片段中,您错误地释放了整数数组 w。您不能释放该数组中的单个整数,但您需要做的只是键入:

free(w);

这将释放整个阵列。 您还可以从错误的文本中看到 - 注意:预期的"void *",但参数的类型为"int"void __cdecl free(void *_Memory),程序期望指向数组的指针而不是整数。

你不能释放旧数组,因为它是静态创建的,并且在程序开始时分配了它的内存,它将在程序本身定义的函数结束时被释放,所以你不需要担心这一点。而您的工作是释放动态创建的数组,例如通过cpy_array(int v[], int size)函数创建的数组。

有关静态分配和动态分配之间区别的更多信息,您可以在此处查找:

静态内存分配和动态内存分配之间的区别

这部分代码不会打印数组(你只会打印数组的第一个数字),而且你还要调用该函数两次,这是多余的,应该只对同一个数组执行一次。

if (*cpy_array(myArray, size) == 0)
{
printf("No memory available.");
}else{
printf("The new Array: %i", *cpy_array(myArray, size)); 
}

您可以通过定义一个可以存储函数返回值的指针来轻松解决这些问题,这样您就不必调用它两次,然后使用 for 循环正确打印数组:

int * copiedArray = cpy_array(myArray, size);
if (copiedArray == NULL)
{
printf("No memory available.");
}else{
printf("The new Array: ");
for (int i = 0; i < size; i++)
printf("%i ", copiedArray[i]); 
}

我注意到您正在检查指针是否指向某物不正确。一旦进入主:

if (*cpy_array(myArray, size) == 0)

一旦进入cpy_array(int v[], int size)功能:

if(*a == 0)

这将不起作用,因为您正在取消引用指针并检查它指向的值是否为零。您要做的是检查指针本身的值。如果为 NULL,则分配不起作用:

if (cpy_array(myArray, size) == NULL)

if(a == NULL)

您应该使用 NULL 而不是零,因为您明确声明您正在检查指针的值,并且 NULL 在每台计算机上可能不等于零。

有关该主题的更多信息,请单击此处:

空、'\0' 和 0 有什么区别

为了检测有关内存使用瓦尔格林德的问题,如果我这样做,可以:

==10947== Memcheck, a memory error detector
==10947== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10947== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10947== Command: ./a.out
==10947== 
==10947== Conditional jump or move depends on uninitialised value(s)
==10947==    at 0x10548: cpy_array (c.c:25)
==10947==    by 0x104B3: main (c.c:11)
==10947== 
==10947== Invalid read of size 4
==10947==    at 0x104B8: main (c.c:11)
==10947==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==10947== 
==10947== 
==10947== Process terminating with default action of signal 11 (SIGSEGV)
==10947==  Access not within mapped region at address 0x0
==10947==    at 0x104B8: main (c.c:11)
==10947==  If you believe this happened as a result of a stack
==10947==  overflow in your program's main thread (unlikely but
==10947==  possible), you can try to increase the size of the
==10947==  main thread stack using the --main-stacksize= flag.
==10947==  The main thread stack size used in this run was 8388608.
==10947== 
==10947== HEAP SUMMARY:
==10947==     in use at exit: 16 bytes in 1 blocks
==10947==   total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==10947== 
==10947== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==10947==    at 0x4847568: malloc (vg_replace_malloc.c:299)
==10947==    by 0x10533: cpy_array (c.c:24)
==10947==    by 0x104B3: main (c.c:11)
==10947== 
==10947== LEAK SUMMARY:
==10947==    definitely lost: 16 bytes in 1 blocks
==10947==    indirectly lost: 0 bytes in 0 blocks
==10947==      possibly lost: 0 bytes in 0 blocks
==10947==    still reachable: 0 bytes in 0 blocks
==10947==         suppressed: 0 bytes in 0 blocks
==10947== 
==10947== For counts of detected and suppressed errors, rerun with: -v
==10947== Use --track-origins=yes to see where uninitialised values come from
==10947== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 3)

"条件跳转或移动取决于未初始化的值">来自if(*a == 0)中的*a"大小为 4 的无效读取...",因为您取消引用 0 是因为return 0;


在将if(*a == 0)更改为if(a == 0)以解决前两个问题后,条件是(先验的)错误的,_valgrind说:

==11116== Memcheck, a memory error detector
==11116== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11116== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11116== Command: ./a.out
==11116== 
Mein neuer Array enthaelt folgende Zeichen: 1==11116== 
==11116== HEAP SUMMARY:
==11116==     in use at exit: 32 bytes in 2 blocks
==11116==   total heap usage: 3 allocs, 1 frees, 1,056 bytes allocated
==11116== 
==11116== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==11116==    at 0x4847568: malloc (vg_replace_malloc.c:299)
==11116==    by 0x10523: cpy_array (c.c:24)
==11116==    by 0x104A3: main (c.c:11)
==11116== 
==11116== 16 bytes in 1 blocks are definitely lost in loss record 2 of 2
==11116==    at 0x4847568: malloc (vg_replace_malloc.c:299)
==11116==    by 0x10523: cpy_array (c.c:24)
==11116==    by 0x104CF: main (c.c:15)
==11116== 
==11116== LEAK SUMMARY:
==11116==    definitely lost: 32 bytes in 2 blocks
==11116==    indirectly lost: 0 bytes in 0 blocks
==11116==      possibly lost: 0 bytes in 0 blocks
==11116==    still reachable: 0 bytes in 0 blocks
==11116==         suppressed: 0 bytes in 0 blocks
==11116== 
==11116== For counts of detected and suppressed errors, rerun with: -v
==11116== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 3)

所以是的,你有内存泄漏,因为你损失了 2 倍的分配回报cpy_array

你需要有类似的东西:

int * v = cpy_array(myArray, size);
if (*v == 0)
{
printf("Speicher kann nicht freigegeben werden.");
}else{
printf("Mein neuer Array enthaelt folgende Zeichen: %i", 
*v);    
}
free(v);

进行修正valgrind没有任何信号:

valgrind --leak-check=full  ./a.out
==11224== Memcheck, a memory error detector
==11224== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11224== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11224== Command: ./a.out
==11224== 
Mein neuer Array enthaelt folgende Zeichen: 1==11224== 
==11224== HEAP SUMMARY:
==11224==     in use at exit: 0 bytes in 0 blocks
==11224==   total heap usage: 2 allocs, 2 frees, 1,040 bytes allocated
==11224== 
==11224== All heap blocks were freed -- no leaks are possible
==11224== 
==11224== For counts of detected and suppressed errors, rerun with: -v
==11224== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

我鼓励你

  • 使用所有警告检测进行编译,例如gcc -g -Wall -pedantic ...
  • 当您遇到问题时,请使用Valgrind和/或调试器
  • 即使你没有看到问题在瓦尔格林德下运行,所以问题可以被隐藏

这不是初始化数组的正确方法

int myArray[4] = {1234};

int myArray[4] = { 1,2,3,4 };

或者干脆

int myArray[] = { 1,2,3,4 };

调用函数cpy_array .. 当你写的时候

if (*cpy_array(myArray, size) == 0)   

不正确,为什么? 因为如果函数返回 NULL,那么您正在取消引用 NULL


在您的函数cpy_array中,您正在取消引用a,这是不正确的,而是比较指针

if ( a == NULL)

并对空指针使用标准常量 NULL,而不是 0,因为它在所有平台上可能不是 0。


相关内容

  • 没有找到相关文章