Return 来自以指针为参数的函数的指针
Return Pointer from function with pointer as param
我正在读这本书:"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;
我的期望:
buffer
上的 ptr
点应该是假的,因为这个范围应该是 broken/cleaned 向上。
我的想法有什么问题吗?
编辑 1
我将 test4(ptr);
更改为 ptr = test4(ptr)
,它仍然有效...
仍然不知道为什么 test4(char* ptr)
正在工作...
char *test4(char *ptr) {
char buffer[10];
ptr = buffer;
strcpy(buffer, "teswert");
return ptr;
}
此代码除了 return 无效指针外没有做任何事情。您的理解是正确的,堆栈指针 returned 无效,不应读取。
这个"works"的原因是因为实际上没有使用那个指针。
test4(ptr);
指针的副本被传递,return值被丢弃,所以它什么都不做。印刷文字来自test3
。举个例子,您可以更改 "testwert"
并且您得到的印刷品完全相同,如果您更改 test3
中的那个,它会更改两个印刷品。所以换句话说,这本书犯了一个错误并用另一个错误隐藏它,然后它没有注意到所有的错误,因为它测试代码有多糟糕(如果它不会 "testwert"
四次,错误会很明显,当然,任何称职的编译器都会发出警告。
我建议把那本书扔掉。
对于 ptr = test4(ptr)
的编辑版本,这是未定义的行为,所以任何事情都可能发生。这包括打印预期的输出、打印垃圾、使程序崩溃或更糟。
您的想法没有错 - 您完全正确。干得好,你现在的 C 编程语言水平比本书作者还高。
这本书一文不值 - 第 3 次修订版,它教授 3 年前的 C 语言的过时版本,其中包含非常糟糕的示例。你刚好 幸运 test4
。将数组的第一个元素的地址放在 some 编译器中只会抑制警告,并且数组恰好位于堆栈中的正确位置并且没有被覆盖。 But GCC 8.3 isn't fooled by using an intermediate variable.
函数中
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):
[...] ignoring the situation completely with unpredictable results [...]
"unpredictable results" 包括它工作的可能性 "as intended"。
上一个公告点列出了其中一个选项
- [Sie verwenden] einen beim Aufruf der Funktion als Argument übergebenen Puffer [...]
即[您将使用]一个缓冲区作为参数传递给函数。对于此选项,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 的数组。
我正在读这本书:"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;
我的期望:
buffer
上的 ptr
点应该是假的,因为这个范围应该是 broken/cleaned 向上。
我的想法有什么问题吗?
编辑 1
我将 test4(ptr);
更改为 ptr = test4(ptr)
,它仍然有效...
仍然不知道为什么 test4(char* ptr)
正在工作...
char *test4(char *ptr) {
char buffer[10];
ptr = buffer;
strcpy(buffer, "teswert");
return ptr;
}
此代码除了 return 无效指针外没有做任何事情。您的理解是正确的,堆栈指针 returned 无效,不应读取。
这个"works"的原因是因为实际上没有使用那个指针。
test4(ptr);
指针的副本被传递,return值被丢弃,所以它什么都不做。印刷文字来自test3
。举个例子,您可以更改 "testwert"
并且您得到的印刷品完全相同,如果您更改 test3
中的那个,它会更改两个印刷品。所以换句话说,这本书犯了一个错误并用另一个错误隐藏它,然后它没有注意到所有的错误,因为它测试代码有多糟糕(如果它不会 "testwert"
四次,错误会很明显,当然,任何称职的编译器都会发出警告。
我建议把那本书扔掉。
对于 ptr = test4(ptr)
的编辑版本,这是未定义的行为,所以任何事情都可能发生。这包括打印预期的输出、打印垃圾、使程序崩溃或更糟。
您的想法没有错 - 您完全正确。干得好,你现在的 C 编程语言水平比本书作者还高。
这本书一文不值 - 第 3 次修订版,它教授 3 年前的 C 语言的过时版本,其中包含非常糟糕的示例。你刚好 幸运 test4
。将数组的第一个元素的地址放在 some 编译器中只会抑制警告,并且数组恰好位于堆栈中的正确位置并且没有被覆盖。 But GCC 8.3 isn't fooled by using an intermediate variable.
函数中
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):
[...] ignoring the situation completely with unpredictable results [...]
"unpredictable results" 包括它工作的可能性 "as intended"。
上一个公告点列出了其中一个选项
- [Sie verwenden] einen beim Aufruf der Funktion als Argument übergebenen Puffer [...]
即[您将使用]一个缓冲区作为参数传递给函数。对于此选项,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 的数组。