【问题标题】:Passing pointer of a pointer in C在C中传递指针的指针
【发布时间】:2020-08-16 05:09:17
【问题描述】:

我目前正在研究如何在 C 中使用指针,如果您不介意,我有几个问题。

我正在尝试处理来自文件的信息,因此 - 为了保持模块化 - 我想将“我的文件”“发送”到几个辅助方法中。

我的问题是:

  1. 我知道,如果我在方法中创建这些文件指针 - 它们会保存在堆栈中。将指针从堆栈内存发送到其他方法是否有问题(从某种意义上说,它可能会导致不需要的行为)?

  2. 我知道如果我将文件的指针发送给其他方法,它实际上会创建它们的副本,这意味着在方法内部更改它们根本不会做任何事情。

这就是为什么我询问“指向指针的指针”的原因,我读过(但不太明白)我可以将辅助方法指针发送到文件指针 - 这样,我就可以处理我的实际文件,而不是一些本地副本。

假设mainFunction 是我用于处理文件的主要方法(它不在“真正的”主要方法中)

void helperFunction1(FILE* file1, FILE* file2)
{
        fclose(outputFile);
        fclose(inputFile);
}

void helperFunction2(FILE* file1, FILE* file2)
{
     **write some stuff into both files**
}

void mainFunction()
{
    FILE* inputFile = fopen(filePath, "r");
    FILE* outputFile = fopen(OUTPUT_FILE_NAME, "w");
    helperFunction2(inputFile, outputFile);
    helperFunction1(inputFile, outputFile);
}

“真实的”inputFileoutputFile 会因调用 helpFunction1 而关闭吗?

“真实的”inputFileoutputFile 会从调用helpFunction2 得到修改(将一些内容写入其中)吗?

我很想对我的问题获得一些见解/答案(我希望它们是有效的,不要太咄咄逼人),我也很想简要解释一下如何使用“指向指针的指针”来修改数据,而不是修改它的一些副本。

【问题讨论】:

  • 你的问题 1 是你不应该担心的。担心理解按指针传递按值传递的区别。
  • 在您的 helperFunction1 中,您需要使用 arguments 的名称(file1file2)并且 not 他们的名称调用函数。
  • 局部变量的生命周期仅在包含它的函数结束时结束。所以问题 1 很简单。
  • if i'll send the pointers of the files to other methods, it will actually create a copy of them, which means that changing them inside the method would not do anything at all. -- 你的目标不是改变指针;就是改变指针指向的数据。
  • 您的代码中没有任何内容需要使用指向指针的指针。

标签: c file pointers


【解决方案1】:

TL/DR - 对于您要执行的操作,helperFunction1helperFunction2 已正确声明,您只需在 helperFunction1 中使用正确的名称。

加长版

如果您希望您的函数修改指针对象本身,那么您必须传递一个指向该指针的指针。这是一个人为的例子,我们想更新一个FILE * 对象:

void open( FILE **ptr, const char *name, const char *mode )
{
  *ptr = fopen( name, mode );
}

int main( void )
{
  FILE *in;   // in stores the address of a FILE object
  FILE *out;  // out stores the address of a FILE object

  open( &in, "input.txt", "r" );   // we are changing the values of in and out
  open( &out, "output.txt", "w" ); // so we must pass pointers to those objects
  ...
}

我们希望open 修改对象inout,因此我们将指针传递给这些对象。

将其与以下内容进行比较:

void write( FILE *ptr, const char *text )
{
  fwrite( ptr, "%s", text );
}

在这种情况下,我们不尝试更改文件指针本身,我们只是尝试写入它指向的FILE 流,因此我们不需要担心指向指针的指针在这种情况下。另一个人为的例子:

int main( void )
{
  FILE *out;
  ...
  write( out, "some text" ); // we are not changing the value of out,
  ...                        // so we do not pass a pointer to it
}

对于任何类型T,如果我们想要一个函数来修改该类型的对象,我们必须传递一个指向该对象的指针:

void foo( T *ptr )
{
  *ptr = new_T_value(); // write a new value to the thing ptr points to
}

int main( void )
{
  T var;
  foo( &var ); // write a new value to var
}

这对于指针类型的工作方式完全相同 - 将 T 替换为 P *

void foo( P * *ptr ) // or just P **ptr
{
  *ptr = new_Pstar_value(); // write a new *pointer* value to the thing ptr points to
}

int main( void )
{
  P * var;
  foo( &var ); // write a new value to var
}

同样,这仅在您想修改var的值时才适用

您可以使用更高级别的间接 - 将 P 替换为 Q *

void foo( Q * * *ptr ) // or just Q ***ptr
{
  *ptr = new_Qstarstar_value(); // write a new *pointer* value to the thing ptr points to
}

int main( void )
{
  Q * * var;   // or just Q **var
  foo( &var ); // write a new value to var
}

foo 中的表达式 foo 中的varmain 中的表达式var 具有相同的类型,因此写入*ptr 等同于写入var

【讨论】:

    【解决方案2】:

    这里有一个简短的例子来说明通过 FILE * 按值(使用)并按地址传递(重新分配)。

    use_file() 中,FILE * 本身没有改变,但 它指向的(不透明的)FILE 的状态被操作改变了 执行。

    change_file() 中,我们可以更改main() 中的fp 变量 因为我们知道它的地址。
    因此,fp 之前并不指向相同的(不透明的)FILE 并在致电change_file() 之后。

    /**
      gcc -std=c99 -o prog_c prog_c.c \
          -pedantic -Wall -Wextra -Wconversion \
          -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
          -g -O0 -UNDEBUG -fsanitize=address,undefined
    
      $ ./prog_c 
      $ cat output_1.txt 
      first line from main()
      something new from use_file()
      about to close in change_file()
      $ cat output_2.txt 
      just open from change_file()
      second line from main()
    **/
    
    #include <stdio.h>
    
    void
    use_file(FILE *f)
    {
      fprintf(f, "something new from %s()\n", __func__);
    }
    
    void
    change_file(FILE **inout_f)
    {
      FILE *f=*inout_f; // load inout-parameter
      fprintf(f, "about to close in %s()\n", __func__);
      fclose(f);
      f=fopen("output_2.txt", "w");
      fprintf(f, "just open from %s()\n", __func__);
      *inout_f=f; // store out-parameter
    }
    
    int
    main(void)
    {
      FILE *fp=fopen("output_1.txt", "w");
      fprintf(fp, "first line from %s()\n", __func__);
      use_file(fp);
      change_file(&fp);
      fprintf(fp, "second line from %s()\n", __func__);
      fclose(fp);
      return 0;
    }
    

    (注意:这里没有检查任何不好的地方,这只是说明性的)

    【讨论】:

      【解决方案3】:

      当你调用一个函数并传递一个参数给它时,C 会复制那个参数。如果它是一个值类型(即它在类型说明符后没有星号),则参数的副本是该值类型的 value。但是如果参数是指针类型,那么被复制的是指针所指向的内存地址。

      这意味着您现在有两个指针指向内存中的相同数据。这也意味着您可以从任一指针引用修改该数据。

      是的,您正在对原始文件进行操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-29
        • 2012-01-05
        • 2013-04-03
        • 2013-05-06
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        相关资源
        最近更新 更多