新手:传递指向函数的指针

NEWBIE: passing a pointer to a function

提问人:Kevin Zembower 提问时间:4/6/2022 最后编辑:Vlad from MoscowKevin Zembower 更新时间:4/6/2022 访问量:78

问:

我正在尝试从大约 5 年前涉足 C 中重新学习 C。具体来说,我正在尝试学习如何从 main 中提取许多操作并将它们制作成一个函数,目的是将它们移动到接下来的库文件中。

这似乎正在起作用:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

struct arguments {
  char *word_file;  /* Default name for input file */
} arguments;

int main (int argc, char *argv[]) {

  arguments.word_file = "dummy";
  
  FILE *fp;
  fp = fopen(arguments.word_file, "r");
  if (fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }

  char word[60];
  fgets (word, sizeof(word), fp);
  printf("Word is %s\n", word);
}

顺便说一句,“虚拟人”是:

$ cat dummy
dog
cat
$ 

无论我如何尝试,它要么给我编译错误,要么在我运行它时出现 seg 错误:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

struct arguments {
  char *word_file;  /* Default name for input file */
} arguments;

void getfile(FILE *fp) {  
  fp = fopen(arguments.word_file, "r");
  if (fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }
}

int main (int argc, char *argv[]) {

  arguments.word_file = "dummy";
  
  FILE *fp;
  getfile(fp);
  
  char word[60];
  fgets (word, sizeof(word), fp);
  printf("Word is %s\n", word);
}

我尝试从 *fp 更改为 fp 再到 &fp,但没有成功。我确信我对文件指针有一些不了解的地方,但无法弄清楚。

感谢您的任何帮助和建议。

-凯文

C 指针 按引用传递 值传递 声明

评论

0赞 user3386109 4/6/2022
C 按值传递参数,因此 in 是与 in 不同的变量。fpgetfilefpmain
0赞 user3386109 4/6/2022
编译器应该在调用您正在使用未初始化变量的行上给出警告。启用编译器警告并修复所有警告非常重要。如果您的编译器是 gcc 或 clang,请使用 .getfile-Wall -Wextra -Werror

答:

1赞 Barmar 4/6/2022 #1

fp不应该是 的参数,它应该是返回值。getfile()

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

struct arguments {
  char *word_file;  /* Default name for input file */
} arguments;

FILE *getfile() {  
  FILE *fp = fopen(arguments.word_file, "r");
  if (fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }
  return fp;
}

int main (int argc, char *argv[]) {

  arguments.word_file = "dummy";
  
  FILE *file_ptr;
  file_ptr = getfile();
  
  char word[60];
  fgets (word, sizeof(word), file_ptr);
  printf("Word is %s\n", word);
}

如果出于某种原因,您确实需要将其作为参数传递,请参阅使用函数更改指针包含的地址

评论

0赞 Kevin Zembower 4/6/2022
感谢您的快速回复。在我看来,这是一种不安全的做法。一旦函数 getfile() 被塞进库文件中,似乎很容易忘记魔术名称是“fp”,有人可能会在主例程中将其重命名为“file_ptr”。
0赞 Barmar 4/6/2022
它不是一个神奇的名字,你可以使用任何你想要的变量。
0赞 Kevin Zembower 4/6/2022
但是我不必在 main 函数和 getfile() 函数中使用“fp”吗?
0赞 Barmar 4/6/2022
不,你为什么会?它只是返回一个值,然后将其分配给调用方中的变量。为什么你认为这与工作方式有什么不同?fp = fopen(...)
0赞 Kevin Zembower 4/6/2022
哇,你是对的,它可以编译并工作。我必须研究这一点才能理解它。再次感谢您的帮助。
1赞 pm100 4/6/2022 #2

您有两个选择

首先,让 'getfile' 返回文件句柄(这是 c 中最惯用的方式)

FILE *getfile() {  
  FILE *fp = fopen(arguments.word_file, "r");
  if (fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }
  return fp;
}

和主要

FILE *fp =  getfile(fp);

或者让 getfile 更新基于 fp 值,使用 C 样式的“按引用传递”

void getfile(FILE **fp) {  
  *fp = fopen(arguments.word_file, "r");
  if (*fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }
}

在主要

File *fp = NULL;
getfile(&fp);

评论

0赞 Kevin Zembower 4/6/2022
非常感谢您的快速回复。我认为你描述的第二种方式是我所想到的。我永远不会得到“**”部分。我得再研究一下。再次感谢。
0赞 pm100 4/6/2022
@KevinZembower将 vlue 作为参数传递给 functin 时,您希望它得到更新 - >您必须传递指向它的指针。在这种情况下,您要传递并已更新的内容本身就是一个指针 -> pass ,具有 arg 类型&fpFILE**
0赞 Vlad from Moscow 4/6/2022 #3

问题在于指针是通过值传递给函数的。fpgetfile

getfile(fp);

也就是说,该函数处理传递指针值的副本。因此,更改函数中的副本不会反映原始指针的值。fp

您需要通过引用传递指针。

在 C 语言中,通过引用传递意味着通过指向对象的指针间接传递对象。取消引用指针,可以直接访问原始对象。

因此,声明并定义函数,例如

void getfile(FILE **fp) {  
  *fp = fopen(arguments.word_file, "r");
  if ( *fp == NULL) { /* If fopen failed... */
    fprintf(stderr, "Error: Unable to open file %s: %s\n",
        arguments.word_file, strerror (errno));
    exit (8);
  }
}

并调用函数

getfile(&fp);

评论

0赞 Kevin Zembower 4/6/2022
非常感谢您的快速回复。我想这就是我所想的。