理解C语言中的fseek()

huangapple go评论58阅读模式
英文:

Understanding fseek() in C

问题

以下是代码的翻译部分:

我正在学习C中的文件I/O,对使用`fwrite()`和`fread()`函数读取和写入结构体到文件感兴趣,现在在我的代码成功运行后,我想知道是否可以从结构体数组中读取特定结构体并将其放入给定的结构体中。<br>
________________________________________________________________________________________________________
*以下是我的尝试*
```c
#include <stdio.h>
#include <stdlib.h>

typedef struct tools {
    int recordno;
    char toolname[50];
    int quantity;
    float cost;
} tools;

void recordprinter(tools a) {
    printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
    FILE *fp;
    
    fp = fopen("file.txt", "rb+");
    tools *a = (tools *)malloc(100 * sizeof(tools));
    for (int i = 0; i < 100; i++) {
        a[i].cost = 0;
        a[i].toolname[0] = 'a';
        a[i].toolname[1] = '
我正在学习C中的文件I/O,对使用`fwrite()`和`fread()`函数读取和写入结构体到文件感兴趣,现在在我的代码成功运行后,我想知道是否可以从结构体数组中读取特定结构体并将其放入给定的结构体中。<br>
________________________________________________________________________________________________________
*以下是我的尝试*
```c
#include <stdio.h>
#include <stdlib.h>

typedef struct tools {
    int recordno;
    char toolname[50];
    int quantity;
    float cost;
} tools;

void recordprinter(tools a) {
    printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
    FILE *fp;
    
    fp = fopen("file.txt", "rb+");
    tools *a = (tools *)malloc(100 * sizeof(tools));
    for (int i = 0; i < 100; i++) {
        a[i].cost = 0;
        a[i].toolname[0] = 'a';
        a[i].toolname[1] = '\0';
        a[i].quantity = 0;
        a[i].recordno = i + 1;
    }
    for (int i = 0; i < 100; i++) {
        fwrite(a + i, sizeof(tools), 1, fp);
        fseek(fp, sizeof(tools), SEEK_CUR);
        // 我在这里使用fseek是因为fwrite在写入文件时不会移动光标。(而fwrite(a + i, sizeof(tools), 100, fp)会导致奇怪的错误)
    }

    fseek(fp, 0, SEEK_SET); // 将光标移回文件的开头。

    fread(a, sizeof(tools), 1, fp);

    fseek(fp, sizeof(tools) * 50, SEEK_SET); // 现在我期望光标位于第51个结构体。

    fread(a + 3, sizeof(tools), 1, fp); // 现在我将第51个结构体写入a[3]

    recordprinter(a[3]);
    // 这会输出26而不是51

    return 0;
}
'
;
a[i].quantity = 0; a[i].recordno = i + 1; } for (int i = 0; i < 100; i++) { fwrite(a + i, sizeof(tools), 1, fp); fseek(fp, sizeof(tools), SEEK_CUR); // 我在这里使用fseek是因为fwrite在写入文件时不会移动光标。(而fwrite(a + i, sizeof(tools), 100, fp)会导致奇怪的错误) } fseek(fp, 0, SEEK_SET); // 将光标移回文件的开头。 fread(a, sizeof(tools), 1, fp); fseek(fp, sizeof(tools) * 50, SEEK_SET); // 现在我期望光标位于第51个结构体。 fread(a + 3, sizeof(tools), 1, fp); // 现在我将第51个结构体写入a[3] recordprinter(a[3]); // 这会输出26而不是51 return 0; }

现在当我运行这个程序时,我期望输出51 a 0 0.00000,但令我惊讶的是它选择了第26个结构并将其放入a[3]。
任何帮助都将不胜感激!


希望这对你有所帮助!

<details>
<summary>英文:</summary>

I was learing File I/O in C and was interested in using it to read and write structures to files via `fwrite()` and `fread()` functions, now after my code ran successfully I was wondering if I could read a specific structure from an array of structures and put it in some given structure.&lt;br&gt;
________________________________________________________________________________________________________
*Here is my attempt at it*

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

typedef struct tools {
int recordno;
char toolname[50];
int quantity;
float cost;
} tools;

void recordprinter(tools a) {
printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
FILE * fp;

fp = fopen(&quot;file.txt&quot;, &quot;rb+&quot;);
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i &lt; 100; i++) {
    a[i].cost = 0;
    a[i].toolname[0] = &#39;a&#39;;
    a[i].toolname[1] = &#39;
fp = fopen(&quot;file.txt&quot;, &quot;rb+&quot;);
tools * a = (tools * ) malloc(100 * sizeof(tools));
for (int i = 0; i &lt; 100; i++) {
a[i].cost = 0;
a[i].toolname[0] = &#39;a&#39;;
a[i].toolname[1] = &#39;\0&#39;;
a[i].quantity = 0;
a[i].recordno = i + 1;
}
for (int i = 0; i &lt; 100; i++) {
fwrite(a + i, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools), SEEK_CUR);
// I used fseek here just because fwrite doesnot move the cursor when\
it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
}
fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.
fread(a, sizeof(tools), 1, fp);
fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.
fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]    
recordprinter(a[3]);
// this gives output 26 and not 51   
return 0;
&#39;; a[i].quantity = 0; a[i].recordno = i + 1; } for (int i = 0; i &lt; 100; i++) { fwrite(a + i, sizeof(tools), 1, fp); fseek(fp, sizeof(tools), SEEK_CUR); // I used fseek here just because fwrite doesnot move the cursor when\ it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches) } fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file. fread(a, sizeof(tools), 1, fp); fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure. fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3] recordprinter(a[3]); // this gives output 26 and not 51 return 0;

}

Now when I ran the programm I expected `51 a 0 0.00000` as output,
but to my surprise it is picking up the 26th structure and putting it in a[3]&lt;br&gt;
Any help will be appritiated!!

</details>


# 答案1
**得分**: 1

尝试将```fopen```的参数从```rb+```改为```w+```。

此外,在创建文件时,移除```fseek```,正如提到的,```fwrite```在写入数据后确实会提前文件偏移量(前提是```fwrite```确实写入数据)。

以下是使用下面修改后的代码观察到的输出:

```text
gcc main.c
./a.out
51 a 0 0.000000
// main.c

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

typedef struct tools {
    int recordno;
    char toolname[50];
    int quantity;
    float cost;
} tools;

void recordprinter(tools a) {
    printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
    FILE *fp;

    // 推荐在这个示例中使用w+
    // w因为它在文件不存在时创建文件
    // r如果文件不存在则失败(在这里似乎没有用)
    // +因为您要读和写
    // 避免b,选择POSIX - Linux
    // 如果libc文档说需要b,则使用b
    // 我的文档“man fopen”说b会被忽略
    fp = fopen("file.txt", "w+");
    // 检查返回值,文件指针存在吗?如果不存在则失败
    if (fp == NULL) { printf("哎呀,文件没有打开\n"); return 1; }
    tools *a = (tools *)malloc(100 * sizeof(tools));
    for (int i = 0; i < 100; i++) {
        a[i].cost = 0;
        a[i].toolname[0] = 'a';
        a[i].toolname[1] = '\0';
        a[i].quantity = 0;
        a[i].recordno = i + 1;
    }
    // 保存100个对象的替代方式
    // if (fwrite(a, sizeof(tools), 100, fp) != 100 )
    // {
    //   printf( "哎呀,没有将100个对象写入文件\n" );
    //  return 1;
    // }
    for (int i = 0; i < 100; i++) {
        fwrite(a + i, sizeof(tools), 1, fp);
        // 移除fseek,不需要,fwrite在这里已经做了需要的事情
        // fseek(fp, sizeof(tools), SEEK_CUR);
        // 我在这里使用fseek仅仅是因为fwrite在写入文件时不移动光标。
        // (而fwrite(a + i, sizeof(tools), 100, fp)会产生奇怪的问题)
    }

    // 在这行之后不再进行审查,似乎作者的意图已经得以实现

    fseek(fp, 0, SEEK_SET); // 将光标返回文件的开头

    fread(a, sizeof(tools), 1, fp);

    fseek(fp, sizeof(tools) * 50, SEEK_SET); // 现在我期望光标在第51个结构体上

    fread(a + 3, sizeof(tools), 1, fp); // 现在我在a[3]中写入第51个结构体

    recordprinter(a[3]);
    // 这将按预期输出51
    return 0;
}
英文:

Try changing fopen to use w+ instead of rb+

Also, remove the fseek when creating the file, as mentioned, fwrite definitely advances the file offset after writing data (provided fwrite does write data at all).

Here is the output observed using the modified code below.

gcc main.c
./a.out
51 a 0 0.000000
// main.c

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

typedef struct tools {
    int recordno;
    char toolname[50];
    int quantity;
    float cost;
} tools;

void recordprinter(tools a) {
    printf(&quot;%d %s %d %f\n&quot;, a.recordno, a.toolname, a.quantity, a.cost);
}

int main() {
    FILE * fp;
    
    // recommend for this example using w+
    // w because it creates the file if the file doesn&#39;t exist
    // r fails if the file doesn&#39;t exist (and that doesn&#39;t seem useful here)
    // + because you are reading and writing
    // avoiding b and choosing POSIX - linux
    // may be wrong, if libc docs says b is needed then use b
    // my doc &quot;man fopen&quot; says b is ignored
    fp = fopen(&quot;file.txt&quot;, &quot;w+&quot;);
    // check return values, file pointer exist? fail if not
    if (fp==NULL) { printf( &quot;oops file not opened\n&quot; ); return 1; }
    tools * a = (tools * ) malloc(100 * sizeof(tools));
    for (int i = 0; i &lt; 100; i++) {
        a[i].cost = 0;
        a[i].toolname[0] = &#39;a&#39;;
        a[i].toolname[1] = &#39;\0&#39;;
        a[i].quantity = 0;
        a[i].recordno = i + 1;
    }
    // alternative way to save 100 objects
    // if ( fwrite(a, sizeof(tools), 100, fp) != 100 )
    // {
    //   printf( &quot;oops 100 objects not written to file\n&quot; );
    //  return 1;
    // }
    for (int i = 0; i &lt; 100; i++) {
        fwrite(a + i, sizeof(tools), 1, fp);
        // remove fseek, not needed, fwrite does what is needed here
        //fseek(fp, sizeof(tools), SEEK_CUR);
        // I used fseek here just because fwrite doesnot move the cursor when
        // it writes something to the file.(and fwrite(a + i, sizeof(tools), 100, fp) gives weird gliches)
    }

    // no review after this line, it seems to do what author intends

    fseek(fp, 0, SEEK_SET); // to bring cursor back to start of the file.

    fread(a, sizeof(tools), 1, fp);

    fseek(fp, sizeof(tools) * 50, SEEK_SET); // now I expect the cursor to be at 51th structure.

    fread(a + 3, sizeof(tools), 1, fp); // I am now writing the 51th structure in a[3]    

    recordprinter(a[3]);
    // this gives output 51 as desired   

    return 0;
}

huangapple
  • 本文由 发表于 2023年2月20日 00:54:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75501798.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定