C、调用fread时消除循环?

C, Eliminating loop when calling fread?

在 C 中我写了这段代码:

char tmp[strlen(argv[1]) + 1];
for (int j = 0; j < strlen(argv[1]) + 1; ++j) {
    fread(&tmp[j], 1, 1, file);
}

我更喜欢消除 for 循环以使代码更短所以它是否等于这个(选项 A):

char tmp[strlen(argv[1]) + 1];
fread(&tmp, 1, strlen(argv[1]) + 1, file);

和这个(选项 B):

char tmp[strlen(argv[1]) + 1];
fread(&tmp, strlen(argv[1]) + 1, 1 ,file);

根据我在 fread 上阅读的内容,两者的答案都是肯定的,但想了解 A 或 B 哪个更可取?

None 选项在我看来是更可取的,并且在不知道你想要实现什么的情况下,没有答案。

从语法来看,您的代码可以编译并且是正确的。从逻辑上看是不可用的。

您在代码中不知道实际读取了多少数据,因此您无法使用存储在 tmp 中的数据。如果您的文件内容大于您的数组或文件不包含空终止符(如果它是文本文件,它很可能不包含)您没有任何类型的指示符有多少字符被读取到您的数组中。

至少您应该存储fread的return值,以了解实际读取了多少数据以及有多少数据有效在你的数组中。另一种方法是用零字节(通过 = {};memset)完全初始化数组,以确保在找到有效数据后找到 nullterminator 或数组已满,因此您可以在以下情况下终止从数组中读取。

记住一些事情:

  1. 循环不是邪恶的,也不会使代码混乱或减慢执行速度,以至于您可以证明在阅读用户输入(恕我直言,文件)时不使用它们是合理的
  2. 您正在处理用户输入,因此会出现意外数据和意外大小。您的代码应该处理该问题,以便编写健壮且容错的代码。
  3. 可能会出现读取错误。因此,如果您想阅读完整文件,请做好准备。例如,如果您的程序被信号中断(至少在 linux 上),阅读将被终止。因此您可能需要多次尝试,因此请阅读整个文件。信号会发生,您不能保证它们不会发生。例如。如果你 fork 了另一个进程,而另一个进程死了,它会触发 SIGCHILD。举个例子。
  4. 您使用 argv[1]strlen 作为您的数组长度。这并没有告诉您 file 的内容是否适合它。因此,您应该澄清您的程序实际应该做什么的问题。此外,如果您认为 file 根据长度或 argv[1] 适合 tmp,它仍然是您阅读的文件,其中可能包含意想不到的内容。

简答:none个选项是正确的(但也许选项B有一定道理)

说明: 您首先要看的是 fread 文档,以了解每个参数的用途: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fread?view=msvc-160

所以第二个参数是以字节为单位的项目大小,第三个参数是要读取的最大项目数。

这意味着在第二个参数中,您应该传递要读取的文件变量内容的总长度。 (如果 strlen(argv[1])+1 包含该长度,您的代码可能有些意义,但这样做不是一个好习惯)。

作为一个建议:不要试图使您的代码只有几行而影响错误控制、可读性或其他问题,并且不要认为用户 (argv) 会很好地使用您的程序。