【问题标题】:Pointers, files and memory management in CC中的指针、文件和内存管理
【发布时间】:2014-12-25 02:08:22
【问题描述】:

我是 C 编程领域的新手,目前我正在同时探索指针、指针算法与文件 IO 和内存管理的组合。请在下面找到我的代码,这就是我想要做的。

我的程序应该使用 malloc 分配 8 字节的堆内存,然后将指针从 malloc 存储到 char*,然后打开一个文件 (text.txt),其中包含以下纯文本行(每个 8 字节长):

图表
chtest2!

然后我尝试使用 fread 从 text.txt 一次读取 8 个字节,直到到达文件末尾。 fread 中读取的 8 个字节存储在之前使用 malloc 分配的内存卡盘中。然后我使用我的 char* 迭代 8 个字节并使用 printf 在标准输出中打印每个字符。每 8 个字节后(直到 EOF),我将指针重置为 8 字节内存块的第 0 个字节并重复直到 EOF。

代码如下:

int main(void)
{
    char* array = malloc(8 * sizeof(char));

    if (array == NULL)
        return 1;

    FILE* inptr = fopen("text.txt", "r");

    if (inptr == NULL)
        return 2;

    while (!feof(inptr))
    {
        fread(array, 8 * sizeof(char), 1, inptr);

        for (int i = 0; i < 8; i++)
        {
            printf("%c", *array);
            array++;
        }
        array -= 8;
    }

    free(array);
    fclose(inptr);
    return 0;
}

请记住,该程序已通过 valgrind 运行,它不会报告任何内存泄漏。这是我得到的输出:

图表
chtest2!
htest2

我不明白第 3 行是从哪里来的。

此外,我不明白为什么当我使用

重置我的 char 指针(数组)时

数组 -= 7;

并通过 valgrind 运行它报告:

泄漏摘要:
==8420== 肯定丢失了:1 个块中的 8 个字节

在逻辑上将 8 个字节的堆内存视为一个字符数组,我们必须将指针返回 7 个位置才能到达点 0,但这种方法似乎会泄漏内存(而数组 -= 8 很好)!

如果有人能对此进行分析,我将不胜感激。谢谢!

【问题讨论】:

  • sizeof(char) 始终为 1
  • 感谢大家的cmets!
  • Bear in bind fread() 不读取行,它读取字节。一行和另一行之间的中断也包含符号,即使它们是不可见的,fread() 也会读取它们。这可能是造成混乱的原因。
  • 此外,fread() 将只读取您告诉它的内容,并填充缓冲区。但是,C 中的正确字符串是以空值结尾的。 fread() 不保证缓冲区将以\0 终止。

标签: c pointers memory-management file-io pointer-arithmetic


【解决方案1】:

正如 cmets 中所指出的,您错误地使用了 feof,这解释了额外的行。至于减去 7 而不是 8:你将 1 加到 array 8 次,那么为什么你会期望减去 7 会让你回到开始的地方呢?

【讨论】:

  • 谢谢,斯科特。我会修改 feof 并且仍然适应基于 0 的系统:)
【解决方案2】:

我对您的代码进行了一些更改,一切正常。这里是:

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

int main(void)
{
    char* array = malloc(9 * sizeof(char)); \\changed

    if (array == NULL)
        return 1;

    FILE* inptr = fopen("file", "r");

    if (inptr == NULL)
        return 2;

    while (!feof(inptr))
    {
        fread(array, 9 * sizeof(char), 1, inptr);  \\changed

        int i=0;
        for (i = 0; i < 8 ; i++)
        {
            if(feof(inptr)) \\added
                goto next;   \\added
            printf("%c", *array);
            array++;
        }
        printf("\n");         \\added
        next:array =array - i;    \\changed
    }    
    free(array);
    fclose(inptr);
    return 0;
}

您需要注意分配的空间文件结尾 EOF 字符和行尾 \n因此,您的程序没有像您预期的那样工作!!!

【讨论】:

  • if(feof(inptr)) 在错误的位置 - 应该在循环之前或之后。你真的应该检查 fread 的 reutn 值。
  • if(feof(inptr)) 来对地方了! :) 它应该在打印或增加指针之前检查EOF 的字符!!!请记住,您有 两个 循环,因此您需要检查循环内而不是循环外的文件结尾!
  • 好吧,您的代码似乎可以工作,但是如果您在不编辑代码的情况下更改 inout 中的行长,现在会出现两个不同的错误,与原始代码相比,只有三行需要更改,
【解决方案3】:

你的文件是

c 987654322 a 987654324 t 987654326 s 987654328 \n 987654330 h 987654332 e 987654334 t 987654336 @!\n

第一个循环读取 8 个字符并打印输出 chartest

第二个循环读取 8 个字符并打印 \nchtest2

第三个循环读取最后两个字符并打印!\nhtest2 这是因为htest2 在读取到文件末尾后留在了缓冲区中。

检查 fread() 的返回值可能会有所帮助

例如:进行这些更改:

               int n = fread(array, sizeof(char), 8, inptr);

               for (int i = 0; i < n; i++)

               array -= i;

【讨论】:

  • 谢谢,杰森。这真的很有帮助!
  • 检查来自fread() 的返回值不仅有帮助;这对代码的正确运行至关重要。
  • 最后一个字符是可疑的 它可能是\n EOF 或只有EOF。这取决于您使用的 EDITOR
  • 正如他的测试所证明的那样,在这种情况下,输出在! @Meninx 之后有\n
  • 实际上我在进行一些编辑时注意到了一些有趣的事情,我注意到geditvim 都会在文件末尾自动添加一个换行符,但其他编辑器没有! ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多