当将char *作为参数传递给函数时,被调用的函数是否应该对该字符串进行自由处理?否则,数据会“丢失”,程序会泄漏数据。或者,编译器以特殊的方式处理char *,以避免每个人都必须一直空闲,并自动删除它,使其超出范围?我将“字符串”传递给该函数,因此不会将实例传递给已存在的char *。或者应该使用char []来代替?只是觉得非常愚蠢的是为参数输入设置一个固定的限制。char *作为函数的参数C
回答
请牢记这一简单原则:“始终释放内存在您分配的相同级别”。换句话说,函数不应该尝试释放它本身没有分配的内存。一个简短的例子来阐明这一点:
#include "graphics.h"
// The graphics API will get a Canvas object for us. This may be newly allocated
// or one from a pool of pre-allocated objects.
Canvas* canvas = graphics_get_canvas();
// If draw_image() frees canvas, that violates the above principle.
// The behavior of the program will be unspecified. So, just draw the image
// and return.
draw_image (canvas);
// This is also a violation.
// free (canvas) ;
// The right thing to do is to give back the Canvas object to the graphics API
// so that it is freed at the same 'level' where it was allocated.
graphics_return_canvas (canvas);
注意,该函数的名称不是graphics_free_canvas()
之类的东西,因为API可以选择释放它或将其返回到池重用。关键是,假定我们没有创建资源的所有权,这是一个非常糟糕的编程实践,除非我们另有具体说明。
这是如何与malloc()和strcmp()的喜欢?他们打算在不同的层面上被释放。事实上,free()本身不会释放内存:-) – paxdiablo 2010-07-20 06:38:42
@paxdiablo,strcmp()?你是说strdup()?如果是这样,我不明白他们是如何在不同的层面上获得释放的。 strcmp()当然不会分配任何东西。 – 2010-07-20 06:41:41
@HH,我不认为他真的是这个意思。答案中概述的原则(清理你自己的混乱)是健全的。避免我以前的一位同事使用的构造函数,他的函数返回一个char *给(文本)答案,在这种情况下,您必须释放它,或者返回错误消息,在这种情况下,您不得释放它。 – 2010-07-20 06:55:35
这听起来像你问这个用法:
void foo(char* str);
foo("test string");
这是一个特殊情况; "test string"
是存储在可执行文件中的字符串表中的常量字符串,不需要释放。 foo
实际上应该采取const char*
来说明,并允许字符串文字存储在非恒定char*
S IN C++
为了扩大这一点,字符串文字“测试字符串”以* static extent *的char(C++中的const char)的12元素数组的形式存在,这意味着它的内存在程序启动时分配并保存到程序退出。当您将字符串文字作为函数参数传递时,编译器**不会**创建字符串的新实例;相反,它传递一个指向现有实例的指针。 – 2010-07-20 18:36:10
已被弃用,软键功能是否应该做一个free
与否取决于谁拥有的字符串。此代码是完全有效的,不会导致任何内存泄漏:
int main()
{
char* s = malloc(.....);
f(s);
free(s);
}
的free
可以内部功能f
,如果它需要字符串的所有权进行为好。但是请注意,由于您假定传递给函数f
的字符串始终使用malloc
或相关函数在堆上进行分配,因此这很危险。如果用户将指针传递给堆栈中分配的字符串,则程序将表现出不可预测的行为。
一般情况下,编译器不会对字符串的内存管理进行任何特殊处理。从编译器的角度来看,它只是一堆字符。
不只是一个堆栈分配的字符串。如果你传递'f()'字符串,并且'f()'试图释放它,你也会遇到麻烦。 – ptomato 2010-07-20 08:58:47
有时API需要一个分配的缓冲区,并且它的功能所有者可以调用该API释放它。
myFunc()
{
char *error = malloc(<max size of error string>);
foo(error);
//Free the pointer here
free(error);
}
像GLIB一些API API的预期指针的声明的变量
myFunc()
{
GError *error;
glib_api(&error);
if (error)
{
printf("Error %s", error-> message);
// can use glib API to free if error is NON NULL but message is allocated by GLIB API
g_error_free(error);
}
}
所以,即使你还没有分配的内存,你需要做的释放,而使用标准库的变量地址。
分配的一块内存(如果未释放)会导致多进程环境中的内存较小,从而降低系统的性能。
看来你已经习惯了OOP风格。我不喜欢OOP,对我来说,如果我在分配后获得一个对象的副本,会很奇怪。在这种情况下,字符串在内存中的某处,其地址以char *形式发送,而不是整个字符串。 另外,请注意,您可以释放()只有malloc()返回的指针,并且只有一次。
用普通的char *
,我会建议总是编写一个策略的代码,调用者“拥有”字符串,并负责释放它,如果它是由malloc
获得的。另一方面,当然可以设想C中的“伪值传递”字符串对象,作为结构实现,其中策略规定在传递字符串时必须放弃字符串的所有权(或者先复制并传递重复)作为论据。如果这个实现使用引用计数的存储来传递对象只是对存储的引用,那么“重复”操作仅仅是一个引用计数增量加上简单的包装器结构分配(或即使通过值结构)。
指向char作为函数变量的指针是指向相同变量的地址,除非它已被替换为常量字符串。你的问题不能用简单的是/否指导来解释;它取决于上下文。在下面的代码中,分别在堆和堆栈上分配的结构通过引用传递以及字符串char *,并将数据插入到结构中。请注意malloc在使用时的不同,但函数的工作原理完全相同。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// struct with all data within
typedef struct d
{
int number;
char name[50];
}data;
// struct with dynamic char *
typedef struct d2
{
int number;
char *name;
}dynamic_data;
// generic function placing data into struct
void InsertData (data * out, int a, char * b)
{
out->number = a;
strcpy(out->name, b);
}
// generic function placing data into second struct
void InsertData2 (dynamic_data * out, int a, char * b)
{
out->number = a;
strcpy(out->name, b);
}
int main (void)
{
char * text = "some string\0";
int n = 20;
// allocated struct
data stuff;
dynamic_data stuff2;
dynamic_data * stuff3;
// need to allocate pointer within struct only
stuff2.name = (char *) malloc(50 * sizeof(char));
// heap allocated struct
stuff3 = (dynamic_data *) malloc(50 * sizeof(dynamic_data));
// heap allocated sub element char *
stuff3->name = (char *) malloc(50 * sizeof(char));
// this is the data
printf ("Pre insertion data\n");
printf ("s=[%s]\n", text);
printf ("n=%d\n", n);
// this is the function insertting
InsertData (&stuff, n, text);
printf ("Post insertion data\n");
printf ("stuff.name=[%s]\n", stuff.name);
printf ("stuff.number=%d\n", stuff.number);
// this is the function inserting
InsertData2 (&stuff2, n, text);
printf ("Post insertion data\n");
printf ("stuff.name=[%s]\n", stuff2.name);
printf ("stuff.number=%d\n", stuff2.number);
//
// This is the segfault version - if nothing was allocated for pointers into
// this function scope, it would crash
// this is the function insertting under a heap allocated
InsertData2 (stuff3, n, text);
printf ("Post insertion data - dynamic version\n");
printf ("stuff3->name=[%s]\n", stuff3->name);
printf ("stuff3->number=%d\n", stuff3->number);
// free in reverse order
free(stuff3->name);
free(stuff3);
free(stuff2.name);
return 0;
}
- 1. C函数参数char * vs char []
- 2. const char *作为C++中的函数参数
- 3. char str []和char * str作为函数参数有什么区别?
- 4. 在C++中将函数参数作为函数参数传递
- 5. 为什么我不能使用char作为函数的参数?
- 6. 函数指针作为参数在C
- 7. 传递C数组为char *函数参数
- 8. 作为函数参数的类C++
- 9. C指针作为函数的参数
- 10. C#枚举作为函数参数?
- 11. C++函数指针作为参数
- 12. 传递char数组作为参数
- 13. 作为参数的函数
- 14. 作为参数的PHP函数参数
- 15. 作为函数参数的Python函数?
- 16. 函数作为函数中的参数
- 17. PHP函数作为函数的参数
- 18. SQL参数为char []
- 19. 以一个类型作为参数的函数C++
- 20. 带有可变参数的函数作为函数C++的参数
- 21. C++:以任意数量参数作为参数传递函数
- 22. 将代码从c#传递给c作为函数参数
- 23. 作为函数的命令行参数C
- 24. C++ lambda表达式作为函数模板中的参数
- 25. 与函数作为参数
- 26. 函数作为参数
- 27. 将多态函数作为参数传递给另一个函数C
- 28. 如何在C/C++中将typedef函数作为参数传递
- 29. 通Java脚本函数作为参数传递给C++函数
- 30. 为什么函数memchr()使用`int`作为`char`类型的参数?
迈克尔的良好答案告诉你考虑将字符串存储在所谓的“静态存储器”中 - 这是存储器在程序映像加载时由操作系统初始化的存储器。 Naveen的例子和free/malloc自己使用“免费商店”,有时称为“堆”。还有“自动存储”通常作为“堆栈”来实现。其他存储可能性是操作系统映射的ABI内存区域,内存映射文件等。一个例子可能是操作系统调用返回当前目录字符串 - 这个“char *”可能指向OS的每线程数据结构。 – 2010-07-20 06:39:32
您通常不应该为参数输入设置固定限制。相反,让调用者给你一个指针,让*他们*告诉你*字符串是多长。 – bta 2010-07-20 16:47:22