从以指针作为参数的函数返回指针

Wul*_*ulf 6 c stack dynamic-memory-allocation stack-memory

我正在读这本书:“ 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;
}
Run Code Online (Sandbox Code Playgroud)

我了解作者在谈论的问题。

为什么test4解决方案有效?

如果我理解正确,不是吗

  1. char buffer[10];在堆栈上分配
  2. 将第一个元素的地址分配buffer给my ptr(在先前作用域中居住)ptr = buffer;

我的期望:

ptron的点buffer应该是错误的,因为该范围应该被破坏/清除。

我的想法出了什么问题?

编辑1

我换test4(ptr);ptr = test4(ptr),它仍然有效?

仍然不知道为什么test4(char* ptr)会起作用...

Ant*_*ala 7

您的想法没有错-您是绝对正确的。好的工作,您现在比使用本书的人更懂C编程语言。

这本书是一文不值的-第三修订版,它以令人毛骨悚然的例子教授了3年前的过时C语言。你正好是幸运test4。将数组的第一个元素的地址放在某些编译器中只会抑制警告,并且数组恰好位于堆栈上的正确位置且不会被覆盖。但是GCC 8.3并没有被中间变量所欺骗。


在功能上

char *test4(char *ptr){
    char buffer[10];
    ptr = buffer;
    strcpy(buffer, "testwert");
    return ptr;
}
Run Code Online (Sandbox Code Playgroud)

ptr在函数内部使用绝不会影响函数外部的指针。它的工作在原来的例子,因为ptr指向从返回的值test3,这是从堆分配。当您将其替换ptr = test4(ptr);ptr变量时,将获得完全不确定的行为,因为它现在指向变量的生命周期。当发生未定义的行为时,程序可能会执行任何操作,包括(C11 3.4.3p1):

[...]完全忽略这种情况,结果不可预测[...]

具有“无法预测的结果”,包括其“按预期”运行的可能性。


上一个公告点列出了以下选项之一:

  • [Sie verwenden] einen beim Aufruf der Funktion als ArgumentübergebenenPuffer [...]

[您将使用]作为参数传递给函数的缓冲区。对于此选项,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;
}
Run Code Online (Sandbox Code Playgroud)

甚至也许

void test4(char *ptr){
    strcpy(ptr, "testval 4");
}
Run Code Online (Sandbox Code Playgroud)

文档指出,在调用此函数之前,ptr应指向至少10 chars 的数组。