我正在尝试使用Eclipse CDT在Ubuntu上编写一个简单的C程序(是的,我对IDE更熟悉,而且我习惯于从Java开发中使用Eclipse),而且我遇到了一些奇怪的东西。在我的代码的一部分,我在函数中初始化一个char数组,默认情况下它指向与其中一个输入相同的位置,这与该char数组无关。这是我的代码:
char* subdir(const char input[], const char dir[]){
[*] int totallen = strlen(input) + strlen(dir) + 2;
char retval[totallen];
strcpy(retval, input);
strcat(retval, dir);
...}
好的,我标有[*]的部分,有一个检查点。即使在那个断点处,当我检查y本地时,我看到retval指向与我的参数输入相同的地址。它甚至不可能,因为输入来自另一个函数,并且在此函数中创建了retval。是我对C没有经验并且缺少某些东西,或者C编译器是否存在某个错误?
对我来说似乎很明显,他们不应该指向同一个(当然,有效的,它们不是NULL)位置。当代码继续时,它实际上会弄乱一切;我在控制台中获得随机字符和形状,程序崩溃。
答案 0 :(得分:2)
我认为检查retval
之前的地址是不合理的,它是一个VLA和所有(根据定义,编译器和调试器对它不太了解,它是在堆栈上的运行时。)
尝试在定义之后检查其地址。
我刚读过“我在控制台中获得随机字符和形状”。现在显而易见的是,你正在返回VLA并希望事情能够发挥作用。
VLA仅在定义的区块内有效。在外面使用它是不明确的行为,因此非常危险。即使大小不变,仍然无效,无法从函数返回。在这种情况下,你绝对希望malloc
记忆。
答案 1 :(得分:2)
cnicutar说。
我讨厌这样做的人,所以我讨厌我......但是...非const大小的数组是C99扩展,不受C ++支持。当然,GCC有扩展来实现它。
在封面下你实际上是_alloca,所以你掏出筹码的几率与谁有权滥用这个功能成正比。
最后,我希望它实际上不会被返回,因为那将返回一个指向堆栈分配数组的指针,这将是你真正的问题,因为该数组在返回时已经消失。
在C ++中,您通常会使用字符串类。
在C中,您可以将指针和长度作为参数传递,或者指向指针(或返回指针),并指定调用完成时应调用free()。这些解决方案都很糟糕,因为它们容易出现泄漏或截断或溢出。 :/
答案 2 :(得分:2)
好吧,你的根本问题是你正在返回指向堆栈分配VLA的指针。你不能这样做。指向局部变量的指针仅在声明它们的函数范围内有效。您的代码会导致未定义的行为。
至少我假设实际代码中.....
的某个位置是return retval
行。
您需要使用堆分配,或者将适当大小的缓冲区传递给函数。
除此之外,在长度计算中只需要+1而不是+2 - 只有一个空终止符。
答案 3 :(得分:1)
尝试将retval
更改为字符指针并使用malloc()
分配缓冲区。
答案 4 :(得分:1)
将两个字符串参数传递为char *或const char *
不应该返回char *,而是应该传递另一个带有字符串指针的参数,该指针已经是malloc的空间。
返回描述函数中发生的事情的bool或int,并使用您传递的参数来存储结果。
最后不要忘记释放内存,因为你需要为堆上的字符串设置malloc空间......
//retstr is not a const like the other two
bool subdir(const char *input, const char *dir,char *retstr){
strcpy(retstr, input);
strcat(retstr, dir);
return 1;
}
int main()
{
char h[]="Hello ";
char w[]="World!";
char *greet=(char*)malloc(strlen(h)+strlen(w)+1); //Size of the result plus room for the terminator!
subdir(h,w,greet);
printf("%s",greet);
return 1;
}
这将打印:“Hello World!”由你的功能加在一起。
另外,当您在动态创建字符串时,您必须使用malloc。编译器不知道其他两个字符串的长度,因此使用char greet [totallen];不应该工作。