来自PHP背景,我习惯于编写返回字符串的小函数(或来自其他函数的响应),如下所示:
function get_something(){
return "foo";
}
然而,我是C的新手,我正试图想办法如何做一些非常基本的事情。
人们可以检讨以下类似的功能,并告诉我它们有何不同,哪一个是最好/最干净的?
char *get_foo(){
char *bar;
bar = "bar";
return bar;
}
char *get_foo(){
char *bar = "bar";
return bar;
}
char *get_foo(){
char *bar = NULL;
bar = "bar";
return bar;
}
char *get_foo(){
return "bar";
}
这些功能之间有什么区别,还是风格问题?
另一件事。如果我有两个函数而另一个调用另一个函数,这样做可以吗?
char *get_foo(){
return "bar";
}
char *get_taz(){
return get_foo();
}
UPDATE :如果get_foo()没有返回const char *,这些函数将如何更改?如果get_foo()调用另一个具有不同长度的char *的函数,该怎么办?
答案 0 :(得分:5)
这四个是等价的,尤其是前三个 - 编译器可能会将它们编译为完全相同的代码。所以我会选择最后一个,因为它更小。
说完了 - 你要返回一个const char *,而不是char *,所以这个特殊的代码可能会破坏一切,具体取决于你如何使用它(如果它完全编译,你可以强迫它)。问题是,您正在查找指向未动态分配的字符串的指针,而是指向可执行映像的一部分。所以修改它可能很危险。
作为一般规则,永远不要返回指向堆栈上分配的东西的指针(即不是使用new或malloc创建的),因为一旦函数结束,该变量的范围也会结束,被破坏,所以你得到指向无效(释放)内存的指针。
答案 1 :(得分:3)
这样的差异无论如何都会被编译器优化 ...我会投票支持:
char *get_foo(){
char *bar = "bar";
return bar;
}
或
const char *get_foo(){
return "bar";
}
或类似的东西(但显然更具防御性,并且在GNU系统上):
char *get_foo(){
return strdup("bar");
}
取决于将来的使用和扩展功能。实际上,由于优化,它是一个可读性问题,以及您希望字符串(可变/不可用)以供将来使用。
因为您正在将变量初始化为程序数据中的常量。如果我动态创建一个字符串,我会做不同的事情。
答案 2 :(得分:1)
与其他人已经说过的一样,编译器可能会为替代品生成相同的代码。但是:你强迫使用C?为什么不在可以使用std :: string类的地方使用C ++。我已经多年没有声明新的char数组 - 太容易出错了。在进入C ++之前,您不需要学习/掌握C语言。
答案 3 :(得分:1)
我总是警惕返回指向较低范围级别上存在的变量的指针。当我几年前第一次学习C-X时,我记得返回一个指向一个用本地范围声明的变量的指针,在我调用printf之前,调试器告诉我一切正常,但它从未打印出正确的值。发生的事情是:变量在printf调用之前是正确的,但是当你调用一个函数时,局部变量在堆栈上被分配,并在返回时被释放,所以我有指针的变量在调用printf之前存在于堆栈上并且是当引发printf函数时,内存被重新分配给printf,从而覆盖了以前的变量。
在你的情况下,你给出的例子将指定一个指向常量表的指针,该表作为可执行文件的一部分加载,并且可能没问题,这取决于实际程序正在做什么,但我会建议保留更高级别范围内的字符串,以防止在您调整时将一个简单的错误隐藏到您的代码中。根据您给出的示例,您可能在此调用上方的范围内分配了一个字符串表,并且只是分配变量而不是调用函数。
即
#define FOO 0
#define BAR 1
#define FOOBAR 2
#define BARFOO 3
char * MyFooStrings [4] = {“Foo”,“Bar”,“FooBar”,“BarFoo”};
//相反:myFoo = get_foo();
myFoo = MyFooStrings [FOO];
皮特
答案 4 :(得分:0)
这些之间有什么区别吗? 功能还是风格问题?
输出方面没有差异。正如其他人所提到的,编译器无论如何都可能优化代码。我的偏好是使用:
char *get_foo(){
char *bar = "bar";
return bar;
}
如果您的返回值比简单赋值更复杂,那么如果您需要单步执行代码,则有助于获得中间变量。
另一件事。如果我有两个 功能和一个调用另一个,是 这样做好吗?
只要您确保两个函数的返回类型兼容,这不是问题。
答案 5 :(得分:0)
更新:这些功能将如何需要 如果get_foo()没有返回则更改 一个const char *?如果get_foo()调用怎么办? 另一个有char *的函数 不同的长度?
get_taz()只需要一个与get_foo()赋值兼容的返回类型。例如,如果get_foo()返回一个int,那么get_taz()必须返回一些你可以赋予int的东西 - 比如int,long int或类似的东西。
“不同长度的char *”实际上没有任何意义,因为“char *”不真正意味着“字符串” - 它意味着“某些的位置炭强>的”。无论该位置是三个字符还是三十个字符,“char *”仍然是“char *”,所以这完全没问题:
const char *get_zero(void)
{
return "Zero";
}
const char *get_nonzero(void)
{
return "The number is non-zero";
}
const char *get_n(int n)
{
if (n == 0)
{
return get_zero();
}
else
{
return get_nonzero();
}
}
答案 6 :(得分:-2)
首先,其中一些会导致程序崩溃。
功能:
char *get_foo(){
char *bar;
bar = "bar";
return bar;
}
是不正确的C代码(它可能不会崩溃,但你永远不会知道)
char *bar
在堆栈上分配1个指针的内存。
就个人而言,我会这样做。
1
char *get_foo1(void) {
char *bar;
bar = malloc(strlen("bar")+1);
sprintf(bar,"bar");
return bar;
}
2。或者传递你分配的变量。
void get_foo2(char **bar) {
sprintf(*bar,"bar);
}
在C中使用字符串时,几乎总是需要malloc()内存才能使用。 除非弦的长度提前知道或非常小。另外,你可以使用上面的#2来避免内存分配,比如这个
int main(int argc, char *argv[]) {
char bar[4];
get_foo2(&bar);
}