char * concat(const char *s1, const char *s2) {
char result[70];
strcpy(result, s1);
strcat(result, s2);
return result;
}
int main() {
char *s1 = "Hello";
char *s2 = " World!";
char *s3 = concat(s1, s2);
printf("%s\n", s3);
return 0;
}
此程序只调用concat
函数,该函数返回char *
,即s1 and s2
的concat。但是,在编译时,我收到错误address of stack memory associated with local variable 'result' returned
。
所以我理解result
是concat函数中的局部变量,但实际上并不是我们为什么需要malloc它。为什么不以Hello World
作为值返回结果?
如果您考虑这样的计划:
int ret() {
int a = 4;
return a;
}
int main() {
int b = ret();
printf("%d\n", b); // 4
return 0;
}
没有错误。我没有malloc的int。 a
是本地的,但我仍然会返回它,它仍然有效。
我想知道concat和ret之间的主要区别是什么,以及为什么concat 必须动态分配内存。谢谢。
答案 0 :(得分:3)
从C标准(6.2.4对象的存储持续时间)
1 对象具有确定其生命周期的存储持续时间。 有四个存储持续时间:静态,线程,自动,和 分配。分配的存储在7.22.3中描述。
2对象的生命周期是程序执行期间的一部分 保证保留哪个存储空间。存在一个对象, 有一个恒定的地址,33)并保留其最后存储的值 在其整个生命周期中.34)如果一个对象被引用到外面 它的生命,行为是不确定的。指针的值 当它指向的对象(或刚刚过去)变得不确定 到达其生命周期的末期。
和
6对于没有可变长度数组类型的对象, 它的生命周期从进入到它所在的区块延伸 关联,直到该块的执行以任何方式结束......
在此功能定义中
char * concat(const char *s1, const char *s2) {
char result[70];
strcpy(result, s1);
strcat(result, s2);
return result;
}
变量result
具有自动存储持续时间。退出函数后,其生命周期结束。因此它写在标准
如果一个对象在其生命周期之外被引用,那么行为就是 未定义。
如果动态分配数组,则退出函数后其生命周期不会结束,指向它的指针将有效。您可以在分配它的函数之外访问已分配的内存。
关于此功能定义
int ret() {
int a = 4;
return a;
}
然后该函数返回对象本身。如果你通过像这样的指针间接返回对象
int * ret() {
int a = 4;
return &a;
}
然后你遇到了与第一个程序相同的问题,如果你尝试使用返回的指针访问变量a
,程序会有未定义的行为。
考虑到函数可以返回int
类型的对象,但它们不能返回数组。
答案 1 :(得分:0)
char * concat(const char *s1, const char *s2) {
char result[70];
strcpy(result, s1);
strcat(result, s2);
return result;
}
在函数中,结果数组在函数调用后被释放,所以
char *s3 = concat(s1, s2);
指针s3指向无效的地址。
答案 2 :(得分:0)
有一些方法可以让这个功能在没有动态内存分配的情况下工作。例如,如果兼容多线程并在函数内部声明一个静态变量,则可以放弃所有希望。插图:
max_words
答案 3 :(得分:-1)
返回类似int
的原语并返回字符串在C中根本不同。字符串不是原始对象,实际上是字符数组。就像你不能在本地声明一个函数中的数组一样,然后返回那个数组,你不能简单地返回字符串。编译器不会抛出错误,而是抛出警告,因为通常情况下,当函数返回时,不会清除存储result
内容的堆栈帧,因此在退出函数后的短时间内,< strong> MIGHT 仍然能够返回指针,但不要指望它。
这里的根本区别是malloc
将在堆上分配空间,除非另有明确说明,否则不会被覆盖,而在函数中声明一个数组并不能保证数组占用的空间仍然存在在函数退出后可访问/可读(因此是局部变量)。