我正在读这本书:“ C von A bis Z”。
有这个例子。
/* ptr14.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Fehler: Funktion gibt die Adresse
* einer lokalen Variablen zurück. */
/* [ Error: Function returns the address of a
a local variable. ] */
// ...
/* Möglichkeit2: Speicher vom Heap verwenden */
/* [ Option2: Use memory from the heap ] */
char *test3(void){
char *buffer = (char *) malloc(10);
strcpy(buffer, "testwert");
return buffer;
}
/* Möglichkeit3: Einen Zeiger als Argument übergeben */
/* [ Option3: Pass a pointer as argument ] */
char *test4(char *ptr){
char buffer[10];
ptr = buffer;
strcpy(buffer, "testwert");
return ptr;
}
int main(void) {
char *ptr;
/* ... */
ptr = test3();
printf("test3: %s\n", ptr);
test4(ptr);
printf("test4: %s\n", ptr);
return EXIT_SUCCESS;
}
我了解作者在谈论的问题。
为什么test4
解决方案有效?
如果我理解正确,不是吗
char buffer[10];
在堆栈上分配buffer
给我ptr
(居住在先前的范围内)ptr = buffer;
我的期望:
带有ptr
on的点buffer
应该是错误的,因为这个范围应该被破坏/清理。
我的想法出了什么问题?
编辑1
我换test4(ptr);
到ptr = test4(ptr)
,它仍然有效?
仍然不知道为什么test4(char* ptr)
会起作用...
您的想法没有错-您是绝对正确的。好的工作,您现在比使用本书的人更懂C编程语言。
这本书是一文不值的-第三修订版,它以令人毛骨悚然的例子教了3年前的过时C语言。你正好是幸运与test4
。在某些编译器中,放置数组第一个元素的地址只是抑制了警告,并且数组恰好位于堆栈上的正确位置,并且不会被覆盖。但是GCC 8.3并没有被中间变量所欺骗。
在功能上
char *test4(char *ptr){
char buffer[10];
ptr = buffer;
strcpy(buffer, "testwert");
return ptr;
}
ptr
在函数内部使用绝不会影响函数外部的指针。它的工作在原来的例子,因为ptr
是仍指向从返回的值test3
,这是从堆分配。当您将其替换ptr = test4(ptr);
为ptr
变量时,将获得完全未定义的行为,因为现在指向变量的生存期。当发生未定义的行为时,程序可能会执行任何操作,包括(C11 3.4.3p1):
[...]完全忽略这种情况,结果不可预测[...]
具有“无法预期的结果”,包括其“按预期”工作的可能性。
上一个公告点列出了以下选项之一:
- [您正在使用]调用该函数时作为参数传递的缓冲区[...]
即[您将使用]作为参数传递给函数的缓冲区。对于此选项,test4
应阅读
// use the **array** starting from *ptr
char *test4(char *ptr){
// use a **different** string here so that you can verify
// that it actually *works* (max 9 characters!)
strcpy(ptr, "testval 4");
return ptr;
}
甚至也许
void test4(char *ptr){
strcpy(ptr, "testval 4");
}
文档指出,在调用此函数之前,ptr
应指向至少10 char
s的数组。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句